You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by il...@apache.org on 2020/06/30 18:04:28 UTC

[ignite] branch ignite-13005 created (now 0e36155)

This is an automated email from the ASF dual-hosted git repository.

ilyak pushed a change to branch ignite-13005
in repository https://gitbox.apache.org/repos/asf/ignite.git.


      at 0e36155  Stylistic fixes.

This branch includes the following new commits:

     new edfa4b8  IGNITE-13005: Spring Data 2 - "JPA style" and working with multiple Ignite instances on same JVM - Fixes #7953.
     new 0e36155  Stylistic fixes.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[ignite] 01/02: IGNITE-13005: Spring Data 2 - "JPA style" and working with multiple Ignite instances on same JVM - Fixes #7953.

Posted by il...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ilyak pushed a commit to branch ignite-13005
in repository https://gitbox.apache.org/repos/asf/ignite.git

commit edfa4b8a1e51316ad3c100bcb0dd33bec749760e
Author: Manuel Núñez <ma...@hotmail.com>
AuthorDate: Tue Jun 30 16:09:48 2020 +0300

    IGNITE-13005: Spring Data 2 - "JPA style" and working with multiple Ignite instances on same JVM - Fixes #7953.
    
    Signed-off-by: Ilya Kasnacheev <il...@gmail.com>
---
 modules/spring-data-2.0/README.txt                 |   15 +
 modules/spring-data-2.0/pom.xml                    |    6 +
 .../springdata20/repository/IgniteRepository.java  |   73 +-
 .../repository/config/DynamicQueryConfig.java      |  401 ++++++++
 .../config/EnableIgniteRepositories.java           |    9 +-
 .../config/IgniteRepositoriesRegistar.java         |    8 +-
 .../IgniteRepositoryConfigurationExtension.java    |   18 +-
 .../springdata20/repository/config/Query.java      |  116 ++-
 .../repository/config/RepositoryConfig.java        |   38 +-
 .../repository/query/DeclaredQuery.java            |  101 ++
 .../repository/query/EmptyDeclaredQuery.java       |   91 ++
 .../query/ExpressionBasedStringQuery.java          |  154 +++
 .../springdata20/repository/query/IgniteQuery.java |   93 +-
 .../repository/query/IgniteQueryGenerator.java     |   33 +-
 .../repository/query/IgniteRepositoryQuery.java    | 1041 ++++++++++++++++---
 .../springdata20/repository/query/QueryUtils.java  |  350 +++++++
 .../springdata20/repository/query/StringQuery.java |  902 +++++++++++++++++
 .../repository/query/spel/SpelEvaluator.java       |  107 ++
 .../repository/query/spel/SpelQueryContext.java    |  370 +++++++
 .../repository/support/ConditionFalse.java         |    7 +-
 .../support/IgniteRepositoryFactory.java           |  239 +++--
 .../support/IgniteRepositoryFactoryBean.java       |   68 +-
 .../repository/support/IgniteRepositoryImpl.java   |  233 +++--
 .../IgniteSpringDataCrudSelfExpressionTest.java    |   61 +-
 .../springdata/IgniteSpringDataCrudSelfTest.java   |  275 ++++--
 .../IgniteSpringDataQueriesSelfTest.java           |  209 +++-
 .../springdata/misc/ApplicationConfiguration.java  |   65 +-
 ...ithCompoundKey.java => FullNameProjection.java} |   18 +-
 .../org/apache/ignite/springdata/misc/Person.java  |    2 +
 ...yWithCompoundKey.java => PersonProjection.java} |   27 +-
 .../ignite/springdata/misc/PersonRepository.java   |   38 +-
 ...va => PersonRepositoryOtherIgniteInstance.java} |   33 +-
 .../misc/PersonRepositoryWithCompoundKey.java      |    2 +-
 .../misc/SampleEvaluationContextExtension.java     |   90 ++
 modules/spring-data-2.2/README.txt                 |   15 +
 modules/spring-data-2.2/pom.xml                    |    6 +
 .../springdata22/repository/IgniteRepository.java  |   73 +-
 .../repository/config/DynamicQueryConfig.java      |  401 ++++++++
 .../config/EnableIgniteRepositories.java           |   10 +-
 .../config/IgniteRepositoriesRegistar.java         |    9 +-
 .../IgniteRepositoryConfigurationExtension.java    |   18 +-
 .../springdata22/repository/config/Query.java      |  116 ++-
 .../repository/config/RepositoryConfig.java        |   38 +
 .../repository/query/DeclaredQuery.java            |  101 ++
 .../repository/query/EmptyDeclaredQuery.java       |   91 ++
 .../query/ExpressionBasedStringQuery.java          |  154 +++
 .../springdata22/repository/query/IgniteQuery.java |   93 +-
 .../repository/query/IgniteQueryGenerator.java     |   33 +-
 .../repository/query/IgniteRepositoryQuery.java    | 1042 +++++++++++++++++---
 .../springdata22/repository/query/QueryUtils.java  |  350 +++++++
 .../springdata22/repository/query/StringQuery.java |  903 +++++++++++++++++
 .../repository/support/ConditionFalse.java         |    7 +-
 .../support/IgniteRepositoryFactory.java           |  239 +++--
 .../support/IgniteRepositoryFactoryBean.java       |   68 +-
 .../repository/support/IgniteRepositoryImpl.java   |  233 +++--
 .../IgniteSpringDataCrudSelfExpressionTest.java    |   62 +-
 .../springdata/IgniteSpringDataCrudSelfTest.java   |  277 ++++--
 .../IgniteSpringDataQueriesSelfTest.java           |  195 +++-
 .../springdata/misc/ApplicationConfiguration.java  |   65 +-
 .../springdata/misc/FullNameProjection.java}       |   18 +-
 .../org/apache/ignite/springdata/misc/Person.java  |    2 +
 .../ignite/springdata/misc/PersonProjection.java}  |   27 +-
 .../ignite/springdata/misc/PersonRepository.java   |   39 +-
 ...va => PersonRepositoryOtherIgniteInstance.java} |   35 +-
 .../misc/PersonRepositoryWithCompoundKey.java      |    2 +-
 .../springdata/misc/PersonSecondRepository.java    |    1 +
 .../misc/SampleEvaluationContextExtension.java     |   90 ++
 parent/pom.xml                                     |    8 +
 68 files changed, 9007 insertions(+), 1107 deletions(-)

diff --git a/modules/spring-data-2.0/README.txt b/modules/spring-data-2.0/README.txt
index f74d97a..d57ec69 100644
--- a/modules/spring-data-2.0/README.txt
+++ b/modules/spring-data-2.0/README.txt
@@ -7,6 +7,21 @@ To enable Spring Data 2.0 module when starting a standalone node, move 'optional
 'libs' folder before running 'ignite.{sh|bat}' script. The content of the module folder will
 be added to classpath in this case.
 
+Main features:
+
+- Supports multiple Ignite instances on same JVM (@RepositoryConfig).
+- Supports query tuning parameters in @Query annotation
+- Supports projections
+- Supports Page and Stream responses
+- Supports Sql Fields Query resultset transformation into the domain entity
+- Supports named parameters (:myParam) into SQL queries, declared using @Param("myParam")
+- Supports advanced parameter binding and SpEL expressions into SQL queries:
+- Template variables:
+    - #entityName - the simple class name of the domain entity
+- Method parameter expressions: Parameters are exposed for indexed access ([0] is the first query method's param) or via the name declared using @Param. The actual SpEL expression binding is triggered by ?#. Example: ?#{[0] or ?#{#myParamName}
+- Advanced SpEL expressions: While advanced parameter binding is a very useful feature, the real power of SpEL stems from the fact, that the expressions can refer to framework abstractions or other application components through SpEL EvaluationContext extension model.
+- Supports SpEL expressions into Text queries (TextQuery).
+
 Importing Spring Data 2.0 Module In Maven Project
 ----------------------------------------
 
diff --git a/modules/spring-data-2.0/pom.xml b/modules/spring-data-2.0/pom.xml
index 7913aac..1e443d0 100644
--- a/modules/spring-data-2.0/pom.xml
+++ b/modules/spring-data-2.0/pom.xml
@@ -130,6 +130,12 @@
         </dependency>
 
         <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>${commons.lang.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.ignite</groupId>
             <artifactId>ignite-core</artifactId>
             <version>${project.version}</version>
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java
index 2e014f1..d311d72 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java
@@ -18,41 +18,92 @@ package org.apache.ignite.springdata20.repository;
 
 import java.io.Serializable;
 import java.util.Map;
+import javax.cache.expiry.ExpiryPolicy;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
 import org.springframework.data.repository.CrudRepository;
+import org.springframework.lang.Nullable;
 
 /**
  * Apache Ignite repository that extends basic capabilities of {@link CrudRepository}.
+ *
+ * @param <V> the cache value type
+ * @param <K> the cache key type
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
-public interface IgniteRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
+public interface IgniteRepository<V, K extends Serializable> extends CrudRepository<V, K> {
+    /**
+     * Returns the Ignite instance bound to the repository
+     *
+     * @return the Ignite instance bound to the repository
+     */
+    public Ignite ignite();
+
+    /**
+     * Returns the Ignite Cache bound to the repository
+     *
+     * @return the Ignite Cache bound to the repository
+     */
+    public IgniteCache<K, V> cache();
+
     /**
      * Saves a given entity using provided key.
      * </p>
-     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates
-     * IDs (keys) that are not unique cluster wide.
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
      *
-     * @param key Entity's key.
+     * @param <S>    Entity type.
+     * @param key    Entity's key.
      * @param entity Entity to save.
-     * @param <S> Entity type.
      * @return Saved entity.
      */
-    <S extends T> S save(ID key, S entity);
+    public <S extends V> S save(K key, S entity);
 
     /**
      * Saves all given keys and entities combinations.
      * </p>
-     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates
-     * IDs (keys) that are not unique cluster wide.
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
      *
+     * @param <S>      type of entities.
      * @param entities Map of key-entities pairs to save.
-     * @param <S> type of entities.
      * @return Saved entities.
      */
-    <S extends T> Iterable<S> save(Map<ID, S> entities);
+    public <S extends V> Iterable<S> save(Map<K, S> entities);
+
+    /**
+     * Saves a given entity using provided key with expiry policy
+     * </p>
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
+     *
+     * @param <S>       Entity type.
+     * @param key       Entity's key.
+     * @param entity    Entity to save.
+     * @param expiryPlc ExpiryPolicy to apply, if not null.
+     * @return Saved entity.
+     */
+    public <S extends V> S save(K key, S entity, @Nullable ExpiryPolicy expiryPlc);
+
+    /**
+     * Saves all given keys and entities combinations with expiry policy
+     * </p>
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
+     *
+     * @param <S>       type of entities.
+     * @param entities  Map of key-entities pairs to save.
+     * @param expiryPlc ExpiryPolicy to apply, if not null.
+     * @return Saved entities.
+     */
+    public <S extends V> Iterable<S> save(Map<K, S> entities, @Nullable ExpiryPolicy expiryPlc);
 
     /**
      * Deletes all the entities for the provided ids.
      *
      * @param ids List of ids to delete.
      */
-    void deleteAllById(Iterable<ID> ids);
+    public void deleteAllById(Iterable<K> ids);
+
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java
new file mode 100644
index 0000000..82bc02c
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java
@@ -0,0 +1,401 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *      http://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 org.apache.ignite.springdata20.repository.config;
+
+/**
+ * Runtime Dynamic query configuration.
+ * <p>
+ * Can be used as special repository method parameter to provide at runtime:
+ * <ol>
+ * <li>Dynamic query string (requires {@link Query#dynamicQuery()} == true)
+ * <li>Ignite query tuning*
+ * </ol>
+ * <p>
+ * * Please, note that {@link Query} annotation parameters will be ignored in favor of those defined in
+ * {@link DynamicQueryConfig} parameter if present.
+ *
+ * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
+ */
+public class DynamicQueryConfig {
+    /**
+     * Value.
+     */
+    private String value = "";
+
+    /**
+     * Text query.
+     */
+    private boolean textQuery;
+
+    /**
+     * Force fields query.
+     */
+    private boolean forceFieldsQry;
+
+    /**
+     * Collocated.
+     */
+    private boolean collocated;
+
+    /**
+     * Timeout.
+     */
+    private int timeout;
+
+    /**
+     * Enforce join order.
+     */
+    private boolean enforceJoinOrder;
+
+    /**
+     * Distributed joins.
+     */
+    private boolean distributedJoins;
+
+    /**
+     * Replicated only.
+     */
+    private boolean replicatedOnly;
+
+    /**
+     * Lazy.
+     */
+    private boolean lazy;
+
+    /**
+     * Local.
+     */
+    private boolean local;
+
+    /**
+     * Parts.
+     */
+    private int[] parts;
+
+    /**
+     * Limit.
+     */
+    private int limit;
+
+    /**
+     * From Query annotation.
+     *
+     * @param queryConfiguration the query configuration
+     * @return the dynamic query config
+     */
+    public static DynamicQueryConfig fromQueryAnnotation(Query queryConfiguration) {
+        DynamicQueryConfig config = new DynamicQueryConfig();
+        if (queryConfiguration != null) {
+            config.value = queryConfiguration.value();
+            config.collocated = queryConfiguration.collocated();
+            config.timeout = queryConfiguration.timeout();
+            config.enforceJoinOrder = queryConfiguration.enforceJoinOrder();
+            config.distributedJoins = queryConfiguration.distributedJoins();
+            config.replicatedOnly = queryConfiguration.replicatedOnly();
+            config.lazy = queryConfiguration.lazy();
+            config.parts = queryConfiguration.parts();
+            config.local = queryConfiguration.local();
+            config.limit = queryConfiguration.limit();
+        }
+        return config;
+    }
+
+    /**
+     * Query text string.
+     *
+     * @return the string
+     */
+    public String value() {
+        return value;
+    }
+
+    /**
+     * Whether must use TextQuery search.
+     *
+     * @return the boolean
+     */
+    public boolean textQuery() {
+        return textQuery;
+    }
+
+    /**
+     * Force SqlFieldsQuery type, deactivating auto-detection based on SELECT statement. Useful for non SELECT
+     * statements or to not return hidden fields on SELECT * statements.
+     *
+     * @return the boolean
+     */
+    public boolean forceFieldsQuery() {
+        return forceFieldsQry;
+    }
+
+    /**
+     * Sets flag defining if this query is collocated.
+     * <p>
+     * Collocation flag is used for optimization purposes of queries with GROUP BY statements. Whenever Ignite executes
+     * a distributed query, it sends sub-queries to individual cluster members. If you know in advance that the elements
+     * of your query selection are collocated together on the same node and you group by collocated key (primary or
+     * affinity key), then Ignite can make significant performance and network optimizations by grouping data on remote
+     * nodes.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     *
+     * @return the boolean
+     */
+    public boolean collocated() {
+        return collocated;
+    }
+
+    /**
+     * Query timeout in millis. Sets the query execution timeout. Query will be automatically cancelled if the execution
+     * timeout is exceeded. Zero value disables timeout
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the int
+     */
+    public int timeout() {
+        return timeout;
+    }
+
+    /**
+     * Sets flag to enforce join order of tables in the query. If set to {@code true} query optimizer will not reorder
+     * tables in join. By default is {@code false}.
+     * <p>
+     * It is not recommended to enable this property until you are sure that your indexes and the query itself are
+     * correct and tuned as much as possible but query optimizer still produces wrong join order.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     *
+     * @return the boolean
+     */
+    public boolean enforceJoinOrder() {
+        return enforceJoinOrder;
+    }
+
+    /**
+     * Specify if distributed joins are enabled for this query.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the boolean
+     */
+    public boolean distributedJoins() {
+        return distributedJoins;
+    }
+
+    /**
+     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the boolean
+     * @deprecated No longer used as of Apache Ignite 2.8.
+     */
+    @Deprecated
+    public boolean replicatedOnly() {
+        return replicatedOnly;
+    }
+
+    /**
+     * Sets lazy query execution flag.
+     * <p>
+     * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
+     * medium result sets this provides optimal performance and minimize duration of internal database locks, thus
+     * increasing concurrency.
+     * <p>
+     * If result set is too big to fit in available memory this could lead to excessive GC pauses and even
+     * OutOfMemoryError. Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory
+     * consumption at the cost of moderate performance hit.
+     * <p>
+     * Defaults to {@code false}, meaning that the whole result set is fetched to memory eagerly.
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     *
+     * @return the boolean
+     */
+    public boolean lazy() {
+        return lazy;
+    }
+
+    /**
+     * Sets whether this query should be executed on local node only.
+     *
+     * @return the boolean
+     */
+    public boolean local() {
+        return local;
+    }
+
+    /**
+     * Sets partitions for a query. The query will be executed only on nodes which are primary for specified
+     * partitions.
+     * <p>
+     * Note what passed array'll be sorted in place for performance reasons, if it wasn't sorted yet.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the int [ ]
+     */
+    public int[] parts() {
+        return parts;
+    }
+
+    /**
+     * Gets limit to response records count for TextQuery. If 0 or less, considered to be no limit.
+     *
+     * @return Limit value.
+     */
+    public int limit() {
+        return limit;
+    }
+
+    /**
+     * Sets value.
+     *
+     * @param value the value
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setValue(String value) {
+        this.value = value;
+        return this;
+    }
+
+    /**
+     * Sets text query.
+     *
+     * @param textQuery the text query
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setTextQuery(boolean textQuery) {
+        this.textQuery = textQuery;
+        return this;
+    }
+
+    /**
+     * Sets force fields query.
+     *
+     * @param forceFieldsQuery the force fields query
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setForceFieldsQuery(boolean forceFieldsQuery) {
+        forceFieldsQry = forceFieldsQuery;
+        return this;
+    }
+
+    /**
+     * Sets collocated.
+     *
+     * @param collocated the collocated
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setCollocated(boolean collocated) {
+        this.collocated = collocated;
+        return this;
+    }
+
+    /**
+     * Sets timeout.
+     *
+     * @param timeout the timeout
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setTimeout(int timeout) {
+        this.timeout = timeout;
+        return this;
+    }
+
+    /**
+     * Sets enforce join order.
+     *
+     * @param enforceJoinOrder the enforce join order
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setEnforceJoinOrder(boolean enforceJoinOrder) {
+        this.enforceJoinOrder = enforceJoinOrder;
+        return this;
+    }
+
+    /**
+     * Sets distributed joins.
+     *
+     * @param distributedJoins the distributed joins
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setDistributedJoins(boolean distributedJoins) {
+        this.distributedJoins = distributedJoins;
+        return this;
+    }
+
+    /**
+     * Sets replicated only.
+     *
+     * @param replicatedOnly the replicated only
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setReplicatedOnly(boolean replicatedOnly) {
+        this.replicatedOnly = replicatedOnly;
+        return this;
+    }
+
+    /**
+     * Sets lazy.
+     *
+     * @param lazy the lazy
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setLazy(boolean lazy) {
+        this.lazy = lazy;
+        return this;
+    }
+
+    /**
+     * Sets local.
+     *
+     * @param local the local
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setLocal(boolean local) {
+        this.local = local;
+        return this;
+    }
+
+    /**
+     * Sets parts.
+     *
+     * @param parts the parts
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setParts(int[] parts) {
+        this.parts = parts;
+        return this;
+    }
+
+    /**
+     * Sets limit to response records count for TextQuery.
+     *
+     * @param limit If 0 or less, considered to be no limit.
+     * @return {@code this} For chaining.
+     */
+    public DynamicQueryConfig setLimit(int limit) {
+        this.limit = limit;
+        return this;
+    }
+
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/EnableIgniteRepositories.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/EnableIgniteRepositories.java
index b1b6016..24b3e70 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/EnableIgniteRepositories.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/EnableIgniteRepositories.java
@@ -41,9 +41,8 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
 @Import(IgniteRepositoriesRegistar.class)
 public @interface EnableIgniteRepositories {
     /**
-     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
-     * {@code @EnableIgniteRepositories("org.my.pkg")} instead of
-     * {@code @EnableIgniteRepositories(basePackages="org.my.pkg")}.
+     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: {@code
+     * @EnableIgniteRepositories("org.my.pkg")} instead of {@code @EnableIgniteRepositories(basePackages="org.my.pkg")}.
      */
     String[] value() default {};
 
@@ -97,8 +96,8 @@ public @interface EnableIgniteRepositories {
     Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
 
     /**
-     * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to
-     * {@link IgniteRepositoryFactoryBean}.
+     * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to {@link
+     * IgniteRepositoryFactoryBean}.
      *
      * @return {@link FactoryBean} class to be used for each repository instance.
      */
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java
index 83ff7ff..546eb2f 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java
@@ -24,12 +24,16 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryBeanDefinitionRegistrarSupport}.
  */
 public class IgniteRepositoriesRegistar extends RepositoryBeanDefinitionRegistrarSupport {
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected Class<? extends Annotation> getAnnotation() {
         return EnableIgniteRepositories.class;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected RepositoryConfigurationExtension getExtension() {
         return new IgniteRepositoryConfigurationExtension();
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
index d770084..9cd36ec 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -27,23 +27,31 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override public String getModuleName() {
         return "Apache Ignite";
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected String getModulePrefix() {
         return "ignite";
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override public String getRepositoryFactoryBeanClassName() {
         return IgniteRepositoryFactoryBean.class.getName();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
-        return Collections.<Class<?>>singleton(IgniteRepository.class);
+        return Collections.singleton(IgniteRepository.class);
     }
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java
index 936f336..394ed43 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.springdata20.repository.config;
 
 import java.lang.annotation.Documented;
@@ -24,14 +23,125 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Annotation to provide a user defined SQL query for a method.
+ * Annotation to provide a user defined query for a method.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface Query {
     /**
-     * SQL query text string.
+     * Query text string. If not provided, Ignite query generator for Spring Data framework will be used to generate one
+     * (only if textQuery = false (default))
      */
     String value() default "";
+
+    /**
+     * Whether annotated repository method must use TextQuery search.
+     */
+    boolean textQuery() default false;
+
+    /**
+     * Force SqlFieldsQuery type, deactivating auto-detection based on SELECT statement. Useful for non SELECT
+     * statements or to not return hidden fields on SELECT * statements.
+     */
+    boolean forceFieldsQuery() default false;
+
+    /**
+     * Sets flag defining if this query is collocated.
+     * <p>
+     * Collocation flag is used for optimization purposes of queries with GROUP BY statements. Whenever Ignite executes
+     * a distributed query, it sends sub-queries to individual cluster members. If you know in advance that the elements
+     * of your query selection are collocated together on the same node and you group by collocated key (primary or
+     * affinity key), then Ignite can make significant performance and network optimizations by grouping data on remote
+     * nodes.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     */
+    boolean collocated() default false;
+
+    /**
+     * Query timeout in millis. Sets the query execution timeout. Query will be automatically cancelled if the execution
+     * timeout is exceeded. Zero value disables timeout
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     */
+    int timeout() default 0;
+
+    /**
+     * Sets flag to enforce join order of tables in the query. If set to {@code true} query optimizer will not reorder
+     * tables in join. By default is {@code false}.
+     * <p>
+     * It is not recommended to enable this property until you are sure that your indexes and the query itself are
+     * correct and tuned as much as possible but query optimizer still produces wrong join order.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     */
+    boolean enforceJoinOrder() default false;
+
+    /**
+     * Specify if distributed joins are enabled for this query.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     */
+    boolean distributedJoins() default false;
+
+    /**
+     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @deprecated No longer used as of Apache Ignite 2.8.
+     */
+    @Deprecated
+    boolean replicatedOnly() default false;
+
+    /**
+     * Sets lazy query execution flag.
+     * <p>
+     * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
+     * medium result sets this provides optimal performance and minimize duration of internal database locks, thus
+     * increasing concurrency.
+     * <p>
+     * If result set is too big to fit in available memory this could lead to excessive GC pauses and even
+     * OutOfMemoryError. Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory
+     * consumption at the cost of moderate performance hit.
+     * <p>
+     * Defaults to {@code false}, meaning that the whole result set is fetched to memory eagerly.
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     */
+    boolean lazy() default false;
+
+    /**
+     * Sets whether this query should be executed on local node only.
+     */
+    boolean local() default false;
+
+    /**
+     * Sets partitions for a query. The query will be executed only on nodes which are primary for specified
+     * partitions.
+     * <p>
+     * Note what passed array'll be sorted in place for performance reasons, if it wasn't sorted yet.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     */
+    int[] parts() default {};
+
+    /**
+     * Specify whether the annotated method must provide a non null {@link DynamicQueryConfig} parameter with a non
+     * empty value (query string) or {@link DynamicQueryConfig#textQuery()} == true.
+     * <p>
+     * Please, note that  {@link DynamicQueryConfig#textQuery()} annotation parameters will be ignored in favor of those
+     * defined in {@link DynamicQueryConfig} parameter if present (runtime ignite query tuning).
+     */
+    boolean dynamicQuery() default false;
+
+    /**
+     * Sets limit to response records count for TextQuery. If 0 or less, considered to be no limit.
+     */
+    int limit() default 0;
+
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/RepositoryConfig.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/RepositoryConfig.java
index 79e60a8..359b75b 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/RepositoryConfig.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/RepositoryConfig.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.springdata20.repository.config;
 
 import java.lang.annotation.Documented;
@@ -23,9 +22,14 @@ import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
 
 /**
  * The annotation can be used to pass Ignite specific parameters to a bound repository.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
@@ -33,7 +37,39 @@ import java.lang.annotation.Target;
 @Inherited
 public @interface RepositoryConfig {
     /**
+     * Cache name string.
+     *
      * @return A name of a distributed Apache Ignite cache an annotated repository will be mapped to.
      */
     String cacheName() default "";
+
+    /**
+     * Ignite instance string. Default "igniteInstance".
+     *
+     * @return {@link Ignite} instance spring bean name
+     */
+    String igniteInstance() default "igniteInstance";
+
+    /**
+     * Ignite cfg string. Default "igniteCfg".
+     *
+     * @return {@link IgniteConfiguration} spring bean name
+     */
+    String igniteCfg() default "igniteCfg";
+
+    /**
+     * Ignite spring cfg path string. Default "igniteSpringCfgPath".
+     *
+     * @return A path to Ignite's Spring XML configuration spring bean name
+     */
+    String igniteSpringCfgPath() default "igniteSpringCfgPath";
+
+    /**
+     * Auto create cache. Default false to enforce control over cache creation and to avoid cache creation by mistake
+     * <p>
+     * Tells to Ignite Repository factory wether cache should be auto created if not exists.
+     *
+     * @return the boolean
+     */
+    boolean autoCreateCache() default false;
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java
new file mode 100644
index 0000000..9edf321
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata20.repository.query;
+
+import java.util.List;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StringUtils;
+
+/**
+ * A wrapper for a String representation of a query offering information about the query.
+ *
+ * @author Jens Schauder
+ * @since 2.0.3
+ */
+interface DeclaredQuery {
+    /**
+     * Creates a {@literal DeclaredQuery} from a query {@literal String}.
+     *
+     * @param qry might be {@literal null} or empty.
+     * @return a {@literal DeclaredQuery} instance even for a {@literal null} or empty argument.
+     */
+    public static DeclaredQuery of(@Nullable String qry) {
+        return StringUtils.isEmpty(qry) ? EmptyDeclaredQuery.EMPTY_QUERY : new StringQuery(qry);
+    }
+
+    /**
+     * @return whether the underlying query has at least one named parameter.
+     */
+    public boolean hasNamedParameter();
+
+    /**
+     * Returns the query string.
+     */
+    public String getQueryString();
+
+    /**
+     * Returns the main alias used in the query.
+     *
+     * @return the alias
+     */
+    @Nullable
+    public String getAlias();
+
+    /**
+     * Returns whether the query is using a constructor expression.
+     *
+     * @since 1.10
+     */
+    public boolean hasConstructorExpression();
+
+    /**
+     * Returns whether the query uses the default projection, i.e. returns the main alias defined for the query.
+     */
+    public boolean isDefaultProjection();
+
+    /**
+     * Returns the {@link StringQuery.ParameterBinding}s registered.
+     */
+    public List<StringQuery.ParameterBinding> getParameterBindings();
+
+    /**
+     * Creates a new {@literal DeclaredQuery} representing a count query, i.e. a query returning the number of rows to
+     * be expected from the original query, either derived from the query wrapped by this instance or from the
+     * information passed as arguments.
+     *
+     * @param cntQry           an optional query string to be used if present.
+     * @param cntQryProjection an optional return type for the query.
+     * @return a new {@literal DeclaredQuery} instance.
+     */
+    public DeclaredQuery deriveCountQuery(@Nullable String cntQry, @Nullable String cntQryProjection);
+
+    /**
+     * @return whether paging is implemented in the query itself, e.g. using SpEL expressions.
+     * @since 2.0.6
+     */
+    public default boolean usesPaging() {
+        return false;
+    }
+
+    /**
+     * Returns whether the query uses JDBC style parameters, i.e. parameters denoted by a simple ? without any index or
+     * name.
+     *
+     * @return Whether the query uses JDBC style parameters.
+     * @since 2.0.6
+     */
+    public boolean usesJdbcStyleParameters();
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java
new file mode 100644
index 0000000..243c36e
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata20.repository.query;
+
+import java.util.Collections;
+import java.util.List;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * NULL-Object pattern implementation for {@link DeclaredQuery}.
+ *
+ * @author Jens Schauder
+ * @since 2.0.3
+ */
+class EmptyDeclaredQuery implements DeclaredQuery {
+    /**
+     * An implementation implementing the NULL-Object pattern for situations where there is no query.
+     */
+    static final DeclaredQuery EMPTY_QUERY = new EmptyDeclaredQuery();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean hasNamedParameter() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String getQueryString() {
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String getAlias() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean hasConstructorExpression() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean isDefaultProjection() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public List<StringQuery.ParameterBinding> getParameterBindings() {
+        return Collections.emptyList();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public DeclaredQuery deriveCountQuery(@Nullable String cntQry, @Nullable String cntQryProjection) {
+        Assert.hasText(cntQry, "CountQuery must not be empty!");
+        return DeclaredQuery.of(cntQry);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean usesJdbcStyleParameters() {
+        return false;
+    }
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java
new file mode 100644
index 0000000..3791985
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2013-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata20.repository.query;
+
+import java.util.regex.Pattern;
+import org.springframework.data.repository.core.EntityMetadata;
+import org.springframework.data.repository.core.RepositoryMetadata;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.util.Assert;
+
+/**
+ * Extension of {@link StringQuery} that evaluates the given query string as a SpEL template-expression.
+ * <p>
+ * Currently the following template variables are available:
+ * <ol>
+ * <li>{@code #entityName} - the simple class name of the given entity</li>
+ * <ol>
+ *
+ * @author Thomas Darimont
+ * @author Oliver Gierke
+ * @author Tom Hombergs
+ */
+class ExpressionBasedStringQuery extends StringQuery {
+    /**
+     * Expression parameter.
+     */
+    private static final String EXPRESSION_PARAMETER = "?#{";
+
+    /**
+     * Quoted expression parameter.
+     */
+    private static final String QUOTED_EXPRESSION_PARAMETER = "?__HASH__{";
+
+    /**
+     * Expression parameter quoting.
+     */
+    private static final Pattern EXPRESSION_PARAMETER_QUOTING = Pattern.compile(Pattern.quote(EXPRESSION_PARAMETER));
+
+    /**
+     * Expression parameter unquoting.
+     */
+    private static final Pattern EXPRESSION_PARAMETER_UNQUOTING = Pattern.compile(
+        Pattern.quote(QUOTED_EXPRESSION_PARAMETER));
+
+    /**
+     * Entity name.
+     */
+    private static final String ENTITY_NAME = "entityName";
+
+    /**
+     * Entity name variable.
+     */
+    private static final String ENTITY_NAME_VARIABLE = "#" + ENTITY_NAME;
+
+    /**
+     * Entity name variable expression.
+     */
+    private static final String ENTITY_NAME_VARIABLE_EXPRESSION = "#{" + ENTITY_NAME_VARIABLE + "}";
+
+    /**
+     * Creates a new instance for the given query and {@link EntityMetadata}.
+     *
+     * @param qry      must not be {@literal null} or empty.
+     * @param metadata must not be {@literal null}.
+     * @param parser   must not be {@literal null}.
+     */
+    public ExpressionBasedStringQuery(String qry, RepositoryMetadata metadata, SpelExpressionParser parser) {
+        super(renderQueryIfExpressionOrReturnQuery(qry, metadata, parser));
+    }
+
+    /**
+     * Creates an instance from a given {@link DeclaredQuery}.
+     *
+     * @param qry      the original query. Must not be {@literal null}.
+     * @param metadata the {@link RepositoryMetadata} for the given entity. Must not be {@literal null}.
+     * @param parser   Parser for resolving SpEL expressions. Must not be {@literal null}.
+     * @return A query supporting SpEL expressions.
+     */
+    static ExpressionBasedStringQuery from(DeclaredQuery qry,
+        RepositoryMetadata metadata,
+        SpelExpressionParser parser) {
+        return new ExpressionBasedStringQuery(qry.getQueryString(), metadata, parser);
+    }
+
+    /**
+     * @param qry,     the query expression potentially containing a SpEL expression. Must not be {@literal null}.}
+     * @param metadata the {@link RepositoryMetadata} for the given entity. Must not be {@literal null}.
+     * @param parser   Must not be {@literal null}.
+     * @return rendered query
+     */
+    private static String renderQueryIfExpressionOrReturnQuery(String qry,
+        RepositoryMetadata metadata,
+        SpelExpressionParser parser) {
+
+        Assert.notNull(qry, "query must not be null!");
+        Assert.notNull(metadata, "metadata must not be null!");
+        Assert.notNull(parser, "parser must not be null!");
+
+        if (!containsExpression(qry))
+            return qry;
+
+        StandardEvaluationContext evalCtx = new StandardEvaluationContext();
+        evalCtx.setVariable(ENTITY_NAME, metadata.getDomainType().getSimpleName());
+
+        qry = potentiallyQuoteExpressionsParameter(qry);
+
+        Expression expr = parser.parseExpression(qry, ParserContext.TEMPLATE_EXPRESSION);
+
+        String result = expr.getValue(evalCtx, String.class);
+
+        if (result == null)
+            return qry;
+
+        return potentiallyUnquoteParameterExpressions(result);
+    }
+
+    /**
+     * @param result Result.
+     */
+    private static String potentiallyUnquoteParameterExpressions(String result) {
+        return EXPRESSION_PARAMETER_UNQUOTING.matcher(result).replaceAll(EXPRESSION_PARAMETER);
+    }
+
+    /**
+     * @param qry Query.
+     */
+    private static String potentiallyQuoteExpressionsParameter(String qry) {
+        return EXPRESSION_PARAMETER_QUOTING.matcher(qry).replaceAll(QUOTED_EXPRESSION_PARAMETER);
+    }
+
+    /**
+     * @param qry Query.
+     */
+    private static boolean containsExpression(String qry) {
+        return qry.contains(ENTITY_NAME_VARIABLE_EXPRESSION);
+    }
+
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java
index 7e626ae..7e75bc2 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java
@@ -17,39 +17,77 @@
 
 package org.apache.ignite.springdata20.repository.query;
 
+import java.util.StringJoiner;
+
 /**
  * Ignite query helper class. For internal use only.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteQuery {
-    /** */
+
+    /**
+     *
+     */
     enum Option {
-        /** Query will be used with Sort object. */
+        /**
+         * Query will be used with Sort object.
+         */
         SORTING,
 
-        /** Query will be used with Pageable object. */
+        /**
+         * Query will be used with Pageable object.
+         */
         PAGINATION,
 
-        /** No advanced option. */
+        /**
+         * No advanced option.
+         */
         NONE
     }
 
-    /** Sql query text string. */
-    private final String sql;
+    /**
+     * Query text string.
+     */
+    private final String qrySql;
 
-    /** */
+    /**
+     * Whether this is a SQL fields query
+     */
     private final boolean isFieldQuery;
 
-    /** Type of option. */
+    /**
+     * Whether this is Text query
+     */
+    private final boolean isTextQuery;
+
+    /**
+     * Whether was autogenerated (by method name)
+     */
+    private final boolean isAutogenerated;
+
+    /**
+     * Type of option.
+     */
     private final Option option;
 
     /**
-     * @param sql Sql.
-     * @param isFieldQuery Is field query.
-     * @param option Option.
+     * @param qrySql          the query string.
+     * @param isFieldQuery    Is field query.
+     * @param isTextQuery     Is a TextQuery
+     * @param isAutogenerated query was autogenerated
+     * @param option          Option.
      */
-    public IgniteQuery(String sql, boolean isFieldQuery, Option option) {
-        this.sql = sql;
+    public IgniteQuery(String qrySql,
+        boolean isFieldQuery,
+        boolean isTextQuery,
+        boolean isAutogenerated,
+        Option option) {
+        this.qrySql = qrySql;
         this.isFieldQuery = isFieldQuery;
+        this.isTextQuery = isTextQuery;
+        this.isAutogenerated = isAutogenerated;
         this.option = option;
     }
 
@@ -58,8 +96,8 @@ public class IgniteQuery {
      *
      * @return SQL query text string.
      */
-    public String sql() {
-        return sql;
+    public String qryStr() {
+        return qrySql;
     }
 
     /**
@@ -72,6 +110,24 @@ public class IgniteQuery {
     }
 
     /**
+     * Returns {@code true} if it's Ignite Text query, {@code false} otherwise.
+     *
+     * @return {@code true} if it's Ignite Text query, {@code false} otherwise.
+     */
+    public boolean isTextQuery() {
+        return isTextQuery;
+    }
+
+    /**
+     * Returns {@code true} if it's autogenerated, {@code false} otherwise.
+     *
+     * @return {@code true} {@code true} if it's autogenerated, {@code false} otherwise.
+     */
+    public boolean isAutogenerated() {
+        return isAutogenerated;
+    }
+
+    /**
      * Advanced querying option.
      *
      * @return querying option.
@@ -79,4 +135,11 @@ public class IgniteQuery {
     public Option options() {
         return option;
     }
+
+    @Override public String toString() {
+        return new StringJoiner(", ", IgniteQuery.class.getSimpleName() + "[", "]").add("qrySql='" + qrySql + "'")
+            .add("isFieldQuery=" + isFieldQuery).add("isTextQuery=" + isTextQuery)
+            .add("isAutogenerated=" + isAutogenerated).add("option=" + option).toString();
+    }
+
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java
index 3648991..f8eb64c 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java
@@ -29,12 +29,17 @@ import org.springframework.data.repository.query.parser.PartTree;
  * Ignite query generator for Spring Data framework.
  */
 public class IgniteQueryGenerator {
+
+    private IgniteQueryGenerator() {
+    }
+
     /**
-     * @param mtd Method.
+     * @param mtd      Method.
      * @param metadata Metadata.
      * @return Generated ignite query.
      */
-    @NotNull public static IgniteQuery generateSql(Method mtd, RepositoryMetadata metadata) {
+    @NotNull
+    public static IgniteQuery generateSql(Method mtd, RepositoryMetadata metadata) {
         PartTree parts = new PartTree(mtd.getName(), metadata.getDomainType());
 
         boolean isCountOrFieldQuery = parts.isCountProjection();
@@ -56,7 +61,7 @@ public class IgniteQueryGenerator {
             if (isCountOrFieldQuery)
                 sql.append("COUNT(1) ");
             else
-                sql.append(" * ");
+                sql.append("* ");
         }
 
         sql.append("FROM ").append(metadata.getDomainType().getSimpleName());
@@ -87,13 +92,13 @@ public class IgniteQueryGenerator {
             sql.append(parts.getMaxResults().intValue());
         }
 
-        return new IgniteQuery(sql.toString(), isCountOrFieldQuery, getOptions(mtd));
+        return new IgniteQuery(sql.toString(), isCountOrFieldQuery, false, true, getOptions(mtd));
     }
 
     /**
      * Add a dynamic part of query for the sorting support.
      *
-     * @param sql SQL text string.
+     * @param sql  SQL text string.
      * @param sort Sort method.
      * @return Sorting criteria in StringBuilder.
      */
@@ -114,6 +119,7 @@ public class IgniteQueryGenerator {
                         case NULLS_LAST:
                             sql.append("LAST");
                             break;
+                        default:
                     }
                 }
                 sql.append(", ");
@@ -128,13 +134,13 @@ public class IgniteQueryGenerator {
     /**
      * Add a dynamic part of a query for the pagination support.
      *
-     * @param sql Builder instance.
+     * @param sql      Builder instance.
      * @param pageable Pageable instance.
      * @return Builder instance.
      */
     public static StringBuilder addPaging(StringBuilder sql, Pageable pageable) {
-        if (pageable.getSort() != null)
-            addSorting(sql, pageable.getSort());
+
+        addSorting(sql, pageable.getSort());
 
         sql.append(" LIMIT ").append(pageable.getPageSize()).append(" OFFSET ").append(pageable.getOffset());
 
@@ -171,7 +177,7 @@ public class IgniteQueryGenerator {
     }
 
     /**
-     * Transform part to sql expression
+     * Transform part to qryStr expression
      */
     private static void handleQueryPart(StringBuilder sql, Part part) {
         sql.append("(");
@@ -212,15 +218,13 @@ public class IgniteQueryGenerator {
             case TRUE:
                 sql.append(" = TRUE");
                 break;
+            //TODO: review this legacy code, LIKE should be -> LIKE ?
+            case LIKE:
             case CONTAINING:
                 sql.append(" LIKE '%' || ? || '%'");
                 break;
             case NOT_CONTAINING:
-                sql.append(" NOT LIKE '%' || ? || '%'");
-                break;
-            case LIKE:
-                sql.append(" LIKE '%' || ? || '%'");
-                break;
+                //TODO: review this legacy code, NOT_LIKE should be -> NOT LIKE ?
             case NOT_LIKE:
                 sql.append(" NOT LIKE '%' || ? || '%'");
                 break;
@@ -249,4 +253,5 @@ public class IgniteQueryGenerator {
 
         sql.append(")");
     }
+
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java
index e445e78..06ed98f 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java
@@ -20,117 +20,444 @@ package org.apache.ignite.springdata20.repository.query;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.AbstractCollection;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Stream;
 import javax.cache.Cache;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.cache.query.TextQuery;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.binary.BinaryUtils;
 import org.apache.ignite.internal.processors.cache.CacheEntryImpl;
+import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
+import org.apache.ignite.internal.processors.cache.binary.IgniteBinaryImpl;
+import org.apache.ignite.internal.processors.cache.query.QueryCursorEx;
+import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.springdata20.repository.config.DynamicQueryConfig;
+import org.apache.ignite.springdata20.repository.query.StringQuery.ParameterBinding;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Slice;
 import org.springframework.data.domain.SliceImpl;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.projection.ProjectionFactory;
 import org.springframework.data.repository.core.RepositoryMetadata;
+import org.springframework.data.repository.query.EvaluationContextProvider;
+import org.springframework.data.repository.query.Parameter;
+import org.springframework.data.repository.query.Parameters;
 import org.springframework.data.repository.query.QueryMethod;
 import org.springframework.data.repository.query.RepositoryQuery;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.util.StringUtils;
 
-import static org.apache.ignite.springdata20.repository.query.IgniteQueryGenerator.addPaging;
-import static org.apache.ignite.springdata20.repository.query.IgniteQueryGenerator.addSorting;
+import static org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactory.isFieldQuery;
 
 /**
- * Ignite SQL query implementation.
+ * Ignite query implementation.
+ * <p>
+ * <p>
+ * Features:
+ * <ol>
+ * <li> Supports query tuning parameters</li>
+ * <li> Supports projections</li>
+ * <li> Supports Page and Stream responses</li>
+ * <li> Supports SqlFieldsQuery resultset transformation into the domain entity</li>
+ * <li> Supports named parameters (:myParam) into SQL queries, declared using @Param("myParam") annotation</li>
+ * <li> Supports advanced parameter binding and SpEL expressions into SQL queries
+ * <ol>
+ * <li><b>Template variables</b>:
+ * <ol>
+ * <li>{@code #entityName} - the simple class name of the domain entity</li>
+ * </ol>
+ * </li>
+ * <li><b>Method parameter expressions</b>: Parameters are exposed for indexed access ([0] is the first query method's
+ * param) or via the name declared using @Param. The actual SpEL expression binding is triggered by '?#'. Example:
+ * ?#{[0]} or ?#{#myParamName}</li>
+ * <li><b>Advanced SpEL expressions</b>: While advanced parameter binding is a very useful feature, the real power of
+ * SpEL stems from the fact, that the expressions can refer to framework abstractions or other application components
+ * through SpEL EvaluationContext extension model.</li>
+ * </ol>
+ * Examples:
+ * <pre>
+ * {@code @Query}(value = "SELECT * from #{#entityName} where email = :email")
+ * User searchUserByEmail({@code @Param}("email") String email);
+ *
+ * {@code @Query}(value = "SELECT * from #{#entityName} where country = ?#{[0]} and city = ?#{[1]}")
+ * List<User> searchUsersByCity({@code @Param}("country") String country, {@code @Param}("city") String city,
+ * Pageable pageable);
+ *
+ * {@code @Query}(value = "SELECT * from #{#entityName} where email = ?")
+ * User searchUserByEmail(String email);
+ *
+ * {@code @Query}(value = "SELECT * from #{#entityName} where lucene = ?#{
+ * luceneQueryBuilder.search().refresh(true).filter(luceneQueryBuilder.match('city',#city)).build()}")
+ * List<User> searchUsersByCity({@code @Param}("city") String city, Pageable pageable);
+ * </pre>
+ * </li>
+ * <li> Supports SpEL expressions into Text queries ({@link TextQuery}). Examples:
+ * <pre>
+ * {@code @Query}(textQuery = true, value = "email: #{#email}")
+ * User searchUserByEmail({@code @Param}("email") String email);
+ *
+ * {@code @Query}(textQuery = true, value = "#{#textToSearch}")
+ * List<User> searchUsersByText({@code @Param}("textToSearch") String text, Pageable pageable);
+ *
+ * {@code @Query}(textQuery = true, value = "#{[0]}")
+ * List<User> searchUsersByText(String textToSearch, Pageable pageable);
+ *
+ * {@code @Query}(textQuery = true, value = "#{luceneQueryBuilder.search().refresh(true).filter(luceneQueryBuilder
+ * .match('city', #city)).build()}")
+ * List<User> searchUserByCity({@code @Param}("city") String city, Pageable pageable);
+ * </pre>
+ * </li>
+ * <li> Supports dynamic query and tuning at runtime by using {@link DynamicQueryConfig} method parameter. Examples:
+ * <pre>
+ * {@code @Query}(value = "SELECT * from #{#entityName} where email = :email")
+ * User searchUserByEmailWithQueryTuning({@code @Param}("email") String email, {@code @Param}("ignoredUsedAsQueryTuning") DynamicQueryConfig config);
+ *
+ * {@code @Query}(dynamicQuery = true)
+ * List<User> searchUsersByCityWithDynamicQuery({@code @Param}("country") String country, {@code @Param}("city") String city,
+ * {@code @Param}("ignoredUsedAsDynamicQueryAndTuning") DynamicQueryConfig config, Pageable pageable);
+ *
+ * ...
+ * DynamicQueryConfig onlyTunning = new DynamicQueryConfig().setCollocated(true);
+ * repo.searchUserByEmailWithQueryTuning("user@mail.com", onlyTunning);
+ *
+ * DynamicQueryConfig withDynamicQuery = new DynamicQueryConfig().value("SELECT * from #{#entityName} where country = ?#{[0] and city = ?#{[1]}").setForceFieldsQuery(true).setLazy(true).setCollocated(true);
+ * repo.searchUsersByCityWithDynamicQuery("Spain", "Madrid", withDynamicQuery, new PageRequest(0, 100));
+ *
+ * </pre>
+ * </li>
+ * </ol>
+ * <p>
+ * Visit <a href="https://docs.hawkore.com/private/apache-ignite-advanced-indexing">Apache Ignite advanced Indexing
+ * Documentation site</a> for more info about Advanced Lucene Index and Lucene Query Builder.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
-@SuppressWarnings({"unchecked", "rawtypes"})
+@SuppressWarnings("unchecked")
 public class IgniteRepositoryQuery implements RepositoryQuery {
-    /** Defines the way how to process query result */
+
+    private static final TreeMap<String, Class<?>> binaryFieldClass = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+    /**
+     * Defines the way how to process query result
+     */
     private enum ReturnStrategy {
-        /** Need to return only one value. */
+        /**
+         * Need to return only one value.
+         */
         ONE_VALUE,
 
-        /** Need to return one cache entry */
+        /**
+         * Need to return one cache entry
+         */
         CACHE_ENTRY,
 
-        /** Need to return list of cache entries */
+        /**
+         * Need to return list of cache entries
+         */
         LIST_OF_CACHE_ENTRIES,
 
-        /** Need to return list of values */
+        /**
+         * Need to return list of values
+         */
         LIST_OF_VALUES,
 
-        /** Need to return list of lists */
+        /**
+         * Need to return list of lists
+         */
         LIST_OF_LISTS,
 
-        /** Need to return slice */
+        /**
+         * Need to return slice
+         */
         SLICE_OF_VALUES,
 
-        /** Slice of cache entries. */
+        /**
+         * Slice of cache entries.
+         */
         SLICE_OF_CACHE_ENTRIES,
 
-        /** Slice of lists. */
-        SLICE_OF_LISTS
+        /**
+         * Slice of lists.
+         */
+        SLICE_OF_LISTS,
+
+        /**
+         * Need to return Page of values
+         */
+        PAGE_OF_VALUES,
+
+        /**
+         * Need to return stream of values
+         */
+        STREAM_OF_VALUES,
     }
 
-    /** Type. */
+    /**
+     * Type.
+     */
     private final Class<?> type;
 
-    /** Sql. */
-    private final IgniteQuery qry;
+    /**
+     * Sql.
+     */
+    private final IgniteQuery staticQuery;
 
-    /** Cache. */
+    /**
+     * Cache.
+     */
     private final IgniteCache cache;
 
-    /** Method. */
+    /**
+     * Ignite instance
+     */
+    private final Ignite ignite;
+
+    /**
+     * required by qryStr field query type for binary manipulation
+     */
+    private IgniteBinaryImpl igniteBinary;
+
+    /**
+     * Ignite bin type.
+     */
+    private BinaryType igniteBinType;
+
+    /**
+     * Method.
+     */
     private final Method mtd;
 
-    /** Metadata. */
+    /**
+     * Metadata.
+     */
     private final RepositoryMetadata metadata;
 
-    /** Factory. */
+    /**
+     * Factory.
+     */
     private final ProjectionFactory factory;
 
-    /** Return strategy. */
-    private final ReturnStrategy returnStgy;
+    /**
+     * Return strategy.
+     */
+    private final ReturnStrategy staticReturnStgy;
 
     /**
-     * @param metadata Metadata.
-     * @param qry Query.
-     * @param mtd Method.
-     * @param factory Factory.
-     * @param cache Cache.
+     * Detect if returned data from method is projected
      */
-    public IgniteRepositoryQuery(RepositoryMetadata metadata, IgniteQuery qry,
-        Method mtd, ProjectionFactory factory, IgniteCache cache) {
-        type = metadata.getDomainType();
-        this.qry = qry;
-        this.cache = cache;
+    private final boolean hasProjection;
+
+    /**
+     * Whether projection is dynamic (provided as method parameter)
+     */
+    private final boolean hasDynamicProjection;
+
+    /**
+     * Dynamic projection parameter index.
+     */
+    private final int dynamicProjectionIndex;
+
+    /**
+     * Dynamic query configuration.
+     */
+    private final int dynamicQueryConfigurationIndex;
+
+    /**
+     * the return query method
+     */
+    private final QueryMethod qMethod;
+
+    /**
+     * the return domain class of QueryMethod
+     */
+    private final Class<?> returnedDomainClass;
+
+    /**
+     * Expression parser.
+     */
+    private final SpelExpressionParser expressionParser;
+
+    /**
+     * could provide ExtensionAwareQueryMethodEvaluationContextProvider
+     */
+    private final EvaluationContextProvider queryMethodEvaluationContextProvider;
+
+    /**
+     * Static query configuration.
+     */
+    private final DynamicQueryConfig staticQueryConfiguration;
+
+    /**
+     * Instantiates a new Ignite repository query.
+     *
+     * @param ignite                               the ignite
+     * @param metadata                             Metadata.
+     * @param staticQuery                          Query.
+     * @param mtd                                  Method.
+     * @param factory                              Factory.
+     * @param cache                                Cache.
+     * @param staticQueryConfiguration             the query configuration
+     * @param queryMethodEvaluationContextProvider the query method evaluation context provider
+     */
+    public IgniteRepositoryQuery(Ignite ignite,
+        RepositoryMetadata metadata,
+        @Nullable IgniteQuery staticQuery,
+        Method mtd,
+        ProjectionFactory factory,
+        IgniteCache cache,
+        @Nullable DynamicQueryConfig staticQueryConfiguration,
+        EvaluationContextProvider queryMethodEvaluationContextProvider) {
         this.metadata = metadata;
         this.mtd = mtd;
         this.factory = factory;
+        type = metadata.getDomainType();
+
+        this.cache = cache;
+        this.ignite = ignite;
+
+        this.staticQueryConfiguration = staticQueryConfiguration;
+        this.staticQuery = staticQuery;
+
+        if (this.staticQuery != null)
+            staticReturnStgy = calcReturnType(mtd, this.staticQuery.isFieldQuery());
+        else
+            staticReturnStgy = null;
+
+        expressionParser = new SpelExpressionParser();
+        this.queryMethodEvaluationContextProvider = queryMethodEvaluationContextProvider;
+
+        qMethod = getQueryMethod();
+
+        // control projection
+        hasDynamicProjection = getQueryMethod().getParameters().hasDynamicProjection();
+        hasProjection = hasDynamicProjection || getQueryMethod().getResultProcessor().getReturnedType()
+            .isProjecting();
+
+        dynamicProjectionIndex = qMethod.getParameters().getDynamicProjectionIndex();
+
+        returnedDomainClass = getQueryMethod().getReturnedObjectType();
+
+        dynamicQueryConfigurationIndex = getDynamicQueryConfigurationIndex(qMethod);
 
-        returnStgy = calcReturnType(mtd, qry.isFieldQuery());
+        // ensure dynamic query configuration param exists if dynamicQuery = true
+        if (dynamicQueryConfigurationIndex == -1 && this.staticQuery == null) {
+            throw new IllegalStateException(
+                "When passing dynamicQuery = true via org.apache.ignite.springdata.repository.config.Query "
+                    + "annotation, you must provide a non null method parameter of type DynamicQueryConfig");
+        }
+        // ensure domain class is registered on marshaller to transform row to entity
+        registerClassOnMarshaller(((IgniteEx)ignite).context(), type);
     }
 
-    /** {@inheritDoc} */
-    @Override public Object execute(Object[] prmtrs) {
-        Query qry = prepareQuery(prmtrs);
+    /**
+     * {@inheritDoc} @param values the values
+     *
+     * @return the object
+     */
+    @Override public Object execute(Object[] values) {
+
+        Object[] parameters = values;
 
-        try (QueryCursor qryCursor = cache.query(qry)) {
-            return transformQueryCursor(prmtrs, qryCursor);
+        // config via Query annotation (dynamicQuery = false)
+        DynamicQueryConfig config = staticQueryConfiguration;
+
+        // or condition to allow query tunning
+        if (config == null || dynamicQueryConfigurationIndex != -1) {
+            DynamicQueryConfig newConfig = (DynamicQueryConfig)values[dynamicQueryConfigurationIndex];
+            parameters = ArrayUtils.removeElement(parameters, dynamicQueryConfigurationIndex);
+            if (newConfig != null) {
+                // upset query configuration
+                config = newConfig;
+            }
         }
+        // query configuration is required, via Query annotation or per parameter (within provided values param)
+        if (config == null) {
+            throw new IllegalStateException(
+                "Unable to execute query. When passing dynamicQuery = true via org.apache.ignite.springdata"
+                    + ".repository.config.Query annotation, you must provide a non null method parameter of type "
+                    + "DynamicQueryConfig");
+        }
+
+        IgniteQuery qry = getQuery(config);
+
+        ReturnStrategy returnStgy = getReturnStgy(qry);
+
+        Query iQry = prepareQuery(qry, config, returnStgy, parameters);
+
+        QueryCursor qryCursor = cache.query(iQry);
+
+        return transformQueryCursor(qry, returnStgy, parameters, qryCursor);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc} @return the query method
+     */
     @Override public QueryMethod getQueryMethod() {
         return new QueryMethod(mtd, metadata, factory);
     }
 
+    private <T extends Parameter> int getDynamicQueryConfigurationIndex(QueryMethod method) {
+        Iterator<T> it = (Iterator<T>)method.getParameters().iterator();
+        int i = 0;
+        boolean found = false;
+        int index = -1;
+        while (it.hasNext()) {
+            T parameter = it.next();
+            if (DynamicQueryConfig.class.isAssignableFrom(parameter.getType())) {
+                if (found) {
+                    throw new IllegalStateException("Invalid '" + method.getName() + "' repository method signature. "
+                        + "Only ONE DynamicQueryConfig parameter is allowed");
+                }
+                found = true;
+                index = i;
+            }
+            i++;
+        }
+        return index;
+    }
+
+    private synchronized IgniteBinaryImpl binary() {
+        if (igniteBinary == null)
+            igniteBinary = (IgniteBinaryImpl)ignite.binary();
+        return igniteBinary;
+    }
+
+    private synchronized BinaryType binType() {
+        if (igniteBinType == null)
+            igniteBinType = binary().type(type);
+        return igniteBinType;
+    }
+
     /**
      * @param mtd Method.
      * @param isFieldQry Is field query.
@@ -139,39 +466,47 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private ReturnStrategy calcReturnType(Method mtd, boolean isFieldQry) {
         Class<?> returnType = mtd.getReturnType();
 
-        if (returnType.isAssignableFrom(ArrayList.class)) {
-            if (isFieldQry) {
-                if (hasAssignableGenericReturnTypeFrom(ArrayList.class, mtd))
-                    return ReturnStrategy.LIST_OF_LISTS;
-            }
-            else if (hasAssignableGenericReturnTypeFrom(Cache.Entry.class, mtd))
-                return ReturnStrategy.LIST_OF_CACHE_ENTRIES;
-
-            return ReturnStrategy.LIST_OF_VALUES;
-        }
-        else if (returnType == Slice.class) {
+        if (returnType == Slice.class) {
             if (isFieldQry) {
                 if (hasAssignableGenericReturnTypeFrom(ArrayList.class, mtd))
                     return ReturnStrategy.SLICE_OF_LISTS;
             }
             else if (hasAssignableGenericReturnTypeFrom(Cache.Entry.class, mtd))
                 return ReturnStrategy.SLICE_OF_CACHE_ENTRIES;
-
             return ReturnStrategy.SLICE_OF_VALUES;
         }
+        else if (returnType == Page.class)
+            return ReturnStrategy.PAGE_OF_VALUES;
+        else if (returnType == Stream.class)
+            return ReturnStrategy.STREAM_OF_VALUES;
         else if (Cache.Entry.class.isAssignableFrom(returnType))
             return ReturnStrategy.CACHE_ENTRY;
+        else if (Iterable.class.isAssignableFrom(returnType)) {
+            if (isFieldQry) {
+                if (hasAssignableGenericReturnTypeFrom(ArrayList.class, mtd))
+                    return ReturnStrategy.LIST_OF_LISTS;
+            }
+            else if (hasAssignableGenericReturnTypeFrom(Cache.Entry.class, mtd))
+                return ReturnStrategy.LIST_OF_CACHE_ENTRIES;
+            return ReturnStrategy.LIST_OF_VALUES;
+        }
         else
             return ReturnStrategy.ONE_VALUE;
     }
 
     /**
-     * @param cls Class 1.
+     * @param cls Class.
      * @param mtd Method.
      * @return if {@code mtd} return type is assignable from {@code cls}
      */
     private boolean hasAssignableGenericReturnTypeFrom(Class<?> cls, Method mtd) {
-        Type[] actualTypeArguments = ((ParameterizedType)mtd.getGenericReturnType()).getActualTypeArguments();
+
+        Type genericReturnType = mtd.getGenericReturnType();
+
+        if (!(genericReturnType instanceof ParameterizedType))
+            return false;
+
+        Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();
 
         if (actualTypeArguments.length == 0)
             return false;
@@ -194,45 +529,140 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     }
 
     /**
-     * @param prmtrs Prmtrs.
-     * @param qryCursor Query cursor.
-     * @return Query cursor or slice
+     * when select fields by query H2 returns Timestamp for types java.util.Date and java.qryStr.Timestamp
+     *
+     * @see org.apache.ignite.internal.processors.query.h2.H2DatabaseType map.put(Timestamp.class, TIMESTAMP)
+     * map.put(java.util.Date.class, TIMESTAMP) map.put(java.qryStr.Date.class, DATE)
      */
-    @Nullable private Object transformQueryCursor(Object[] prmtrs, QueryCursor qryCursor) {
-        if (qry.isFieldQuery()) {
-            Iterable<List> qryIter = (Iterable<List>)qryCursor;
+    private static <T> T fixExpectedType(final Object object, final Class<T> expected) {
+        if (expected != null && object instanceof java.sql.Timestamp && expected.equals(java.util.Date.class))
+            return (T)new java.util.Date(((java.sql.Timestamp)object).getTime());
+        return (T)object;
+    }
 
-            switch (returnStgy) {
-                case LIST_OF_VALUES:
-                    List list = new ArrayList<>();
+    /**
+     * @param cfg Config.
+     */
+    private IgniteQuery getQuery(@Nullable DynamicQueryConfig cfg) {
+        if (staticQuery != null)
+            return staticQuery;
+        if (cfg != null && (StringUtils.hasText(cfg.value()) || cfg.textQuery())) {
+            return new IgniteQuery(cfg.value(),
+                !cfg.textQuery() && (isFieldQuery(cfg.value()) || cfg.forceFieldsQuery()), cfg.textQuery(),
+                false, IgniteQueryGenerator.getOptions(mtd));
+        }
+        throw new IllegalStateException("Unable to obtain a valid query. When passing dynamicQuery = true via org"
+            + ".apache.ignite.springdata.repository.config.Query annotation, you must"
+            + " provide a non null method parameter of type DynamicQueryConfig with a "
+            + "non empty value (query string) or textQuery = true");
+    }
 
-                    for (List entry : qryIter)
-                        list.add(entry.get(0));
+    /**
+     * @param qry Query.
+     */
+    private ReturnStrategy getReturnStgy(IgniteQuery qry) {
+        if (staticReturnStgy != null)
+            return staticReturnStgy;
+        if (qry != null)
+            return calcReturnType(mtd, qry.isFieldQuery());
+        throw new IllegalStateException("Unable to obtain a valid return strategy. When passing dynamicQuery = true "
+            + "via org.apache.ignite.springdata.repository.config.Query annotation, "
+            + "you must provide a non null method parameter of type "
+            + "DynamicQueryConfig with a non empty value (query string) or textQuery "
+            + "= true");
+    }
 
-                    return list;
+    /**
+     * @param cls Class.
+     */
+    private static boolean isPrimitiveOrWrapper(Class<?> cls) {
+        return cls.isPrimitive() ||
+            Boolean.class.equals(cls) ||
+            Byte.class.equals(cls) ||
+            Character.class.equals(cls) ||
+            Short.class.equals(cls) ||
+            Integer.class.equals(cls) ||
+            Long.class.equals(cls) ||
+            Float.class.equals(cls) ||
+            Double.class.equals(cls) ||
+            Void.class.equals(cls) ||
+            String.class.equals(cls) ||
+            UUID.class.equals(cls);
+    }
 
-                case ONE_VALUE:
-                    Iterator<List> iter = qryIter.iterator();
+    /**
+     * @param prmtrs    Prmtrs.
+     * @param qryCursor Query cursor.
+     * @return Query cursor or slice
+     */
+    @Nullable
+    private Object transformQueryCursor(IgniteQuery qry,
+        ReturnStrategy returnStgy,
+        Object[] prmtrs,
+        QueryCursor qryCursor) {
+
+        final Class<?> returnClass;
+
+        if (hasProjection) {
+            if (hasDynamicProjection)
+                returnClass = (Class<?>)prmtrs[dynamicProjectionIndex];
+            else
+                returnClass = returnedDomainClass;
+        }
+        else
+            returnClass = returnedDomainClass;
 
-                    if (iter.hasNext())
-                        return iter.next().get(0);
+        if (qry.isFieldQuery()) {
+            // take control over single primite result from queries, i.e. DELETE, SELECT COUNT, UPDATE ...
+            boolean singlePrimitiveResult = isPrimitiveOrWrapper(returnClass);
 
-                    return null;
+            final List<GridQueryFieldMetadata> meta = ((QueryCursorEx)qryCursor).fieldsMeta();
 
-                case SLICE_OF_VALUES:
-                    List content = new ArrayList<>();
+            Function<List<?>, ?> cWrapperTransformFunction = null;
 
-                    for (List entry : qryIter)
-                        content.add(entry.get(0));
+            if (type.equals(returnClass)) {
+                IgniteBinaryImpl binary = binary();
+                BinaryType binType = binType();
+                cWrapperTransformFunction = row -> rowToEntity(binary, binType, row, meta);
+            }
+            else {
+                if (hasProjection || singlePrimitiveResult) {
+                    if (singlePrimitiveResult)
+                        cWrapperTransformFunction = row -> row.get(0);
+                    else {
+                        // Map row -> projection class
+                        cWrapperTransformFunction = row -> factory
+                            .createProjection(returnClass, rowToMap(row, meta));
+                    }
+                }
+                else
+                    cWrapperTransformFunction = row -> rowToMap(row, meta);
+            }
 
-                    return new SliceImpl(content, (Pageable)prmtrs[prmtrs.length - 1], true);
+            QueryCursorWrapper<?, ?> cWrapper = new QueryCursorWrapper<>((QueryCursor<List<?>>)qryCursor,
+                cWrapperTransformFunction);
 
+            switch (returnStgy) {
+                case PAGE_OF_VALUES:
+                    return new PageImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], 0);
+                case LIST_OF_VALUES:
+                    return cWrapper.getAll();
+                case STREAM_OF_VALUES:
+                    return cWrapper.stream();
+                case ONE_VALUE:
+                    Iterator<?> iter = cWrapper.iterator();
+                    if (iter.hasNext()) {
+                        Object resp = iter.next();
+                        U.closeQuiet(cWrapper);
+                        return resp;
+                    }
+                    return null;
+                case SLICE_OF_VALUES:
+                    return new SliceImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
                 case SLICE_OF_LISTS:
                     return new SliceImpl(qryCursor.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
-
                 case LIST_OF_LISTS:
                     return qryCursor.getAll();
-
                 default:
                     throw new IllegalStateException();
             }
@@ -240,87 +670,444 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         else {
             Iterable<CacheEntryImpl> qryIter = (Iterable<CacheEntryImpl>)qryCursor;
 
-            switch (returnStgy) {
-                case LIST_OF_VALUES:
-                    List list = new ArrayList<>();
+            Function<CacheEntryImpl, ?> cWrapperTransformFunction;
 
-                    for (CacheEntryImpl entry : qryIter)
-                        list.add(entry.getValue());
+            if (hasProjection && !type.equals(returnClass))
+                cWrapperTransformFunction = row -> factory.createProjection(returnClass, row.getValue());
+            else
+                cWrapperTransformFunction = row -> row.getValue();
 
-                    return list;
+            QueryCursorWrapper<?, ?> cWrapper = new QueryCursorWrapper<>((QueryCursor<CacheEntryImpl>)qryCursor,
+                cWrapperTransformFunction);
 
+            switch (returnStgy) {
+                case PAGE_OF_VALUES:
+                    return new PageImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], 0);
+                case LIST_OF_VALUES:
+                    return cWrapper.getAll();
+                case STREAM_OF_VALUES:
+                    return cWrapper.stream();
                 case ONE_VALUE:
-                    Iterator<CacheEntryImpl> iter1 = qryIter.iterator();
+                    Iterator<?> iter1 = cWrapper.iterator();
+                    if (iter1.hasNext()) {
+                        Object resp = iter1.next();
+                        U.closeQuiet(cWrapper);
+                        return resp;
+                    }
+                    return null;
+                case CACHE_ENTRY:
+                    Iterator<?> iter2 = qryIter.iterator();
+                    if (iter2.hasNext()) {
+                        Object resp2 = iter2.next();
+                        U.closeQuiet(qryCursor);
+                        return resp2;
+                    }
+                    return null;
+                case SLICE_OF_VALUES:
+                    return new SliceImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
+                case SLICE_OF_CACHE_ENTRIES:
+                    return new SliceImpl(qryCursor.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
+                case LIST_OF_CACHE_ENTRIES:
+                    return qryCursor.getAll();
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+    }
 
-                    if (iter1.hasNext())
-                        return iter1.next().getValue();
+    /**
+     * Extract bindable values
+     *
+     * @param values            values invoking query method
+     * @param queryMethodParams query method parameter definitions
+     * @param queryBindings     All parameters found on query string that need to be binded
+     * @return new list of parameters
+     */
+    private Object[] extractBindableValues(Object[] values,
+        Parameters<?, ?> queryMethodParams,
+        List<ParameterBinding> queryBindings) {
+
+        // no binding params then exit
+        if (queryBindings.isEmpty())
+            return values;
+
+        Object[] newValues = new Object[queryBindings.size()];
+
+        // map bindable parameters from query method: (index/name) - index
+        HashMap<String, Integer> methodParams = new HashMap<>();
+
+        // create an evaluation context for custom query
+        EvaluationContext queryEvalContext = queryMethodEvaluationContextProvider
+            .getEvaluationContext(queryMethodParams, values);
+
+        // By default queryEvalContext:
+        // - make accesible query method parameters by index:
+        // @Query("select u from User u where u.age = ?#{[0]}")
+        // List<User> findUsersByAge(int age);
+        // - make accesible query method parameters by name:
+        // @Query("select u from User u where u.firstname = ?#{#customer.firstname}")
+        // List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
+
+        // query method param's index by name and position
+        queryMethodParams.getBindableParameters().forEach(p -> {
+            if (p.isNamedParameter()) {
+                // map by name (annotated by @Param)
+                methodParams.put(p.getName().get(), p.getIndex());
+            }
+            // map by position
+            methodParams.put(String.valueOf(p.getIndex()), p.getIndex());
+        });
 
-                    return null;
+        // process all parameters on query and extract new values to bind
+        for (int i = 0; i < queryBindings.size(); i++) {
+            ParameterBinding p = queryBindings.get(i);
 
-                case CACHE_ENTRY:
-                    Iterator<CacheEntryImpl> iter2 = qryIter.iterator();
+            if (p.isExpression()) {
+                // Evaluate SpEl expressions (synthetic parameter value) , example ?#{#customer.firstname}
+                newValues[i] = expressionParser.parseExpression(p.getExpression()).getValue(queryEvalContext);
+            }
+            else {
+                // Extract parameter value by name or position respectively from invoking values
+                newValues[i] = values[methodParams.get(
+                    p.getName() != null ? p.getName() : String.valueOf(p.getRequiredPosition() - 1))];
+            }
+        }
 
-                    if (iter2.hasNext())
-                        return iter2.next();
+        return newValues;
+    }
 
-                    return null;
+    /**
+     * @param qry        Query.
+     * @param config     Config.
+     * @param returnStgy Return stgy.
+     * @param values     Values.
+     * @return prepared query for execution
+     */
+    @NotNull
+    private Query prepareQuery(IgniteQuery qry, DynamicQueryConfig config, ReturnStrategy returnStgy, Object[] values) {
 
-                case SLICE_OF_VALUES:
-                    List content = new ArrayList<>();
+        Object[] parameters = values;
 
-                    for (CacheEntryImpl entry : qryIter)
-                        content.add(entry.getValue());
+        String queryString = qry.qryStr();
 
-                    return new SliceImpl(content, (Pageable)prmtrs[prmtrs.length - 1], true);
+        Query query;
 
-                case SLICE_OF_CACHE_ENTRIES:
-                    return new SliceImpl(qryCursor.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
+        checkRequiredPageable(returnStgy, values);
 
-                case LIST_OF_CACHE_ENTRIES:
-                    return qryCursor.getAll();
+        if (!qry.isTextQuery()) {
 
+            if (!qry.isAutogenerated()) {
+                StringQuery squery = new ExpressionBasedStringQuery(queryString, metadata, expressionParser);
+                queryString = squery.getQueryString();
+                parameters = extractBindableValues(parameters, getQueryMethod().getParameters(),
+                    squery.getParameterBindings());
+            }
+            else {
+                // remove dynamic projection from parameters
+                if (hasDynamicProjection)
+                    parameters = ArrayUtils.remove(parameters, dynamicProjectionIndex);
+            }
+
+            switch (qry.options()) {
+                case SORTING:
+                    queryString = IgniteQueryGenerator
+                        .addSorting(new StringBuilder(queryString), (Sort)values[values.length - 1])
+                        .toString();
+                    if (qry.isAutogenerated())
+                        parameters = Arrays.copyOfRange(parameters, 0, values.length - 1);
+                    break;
+                case PAGINATION:
+                    queryString = IgniteQueryGenerator
+                        .addPaging(new StringBuilder(queryString), (Pageable)values[values.length - 1])
+                        .toString();
+                    if (qry.isAutogenerated())
+                        parameters = Arrays.copyOfRange(parameters, 0, values.length - 1);
+                    break;
                 default:
-                    throw new IllegalStateException();
+            }
+
+            if (qry.isFieldQuery()) {
+                SqlFieldsQuery sqlFieldsQry = new SqlFieldsQuery(queryString);
+                sqlFieldsQry.setArgs(parameters);
+
+                sqlFieldsQry.setCollocated(config.collocated());
+                sqlFieldsQry.setDistributedJoins(config.distributedJoins());
+                sqlFieldsQry.setEnforceJoinOrder(config.enforceJoinOrder());
+                sqlFieldsQry.setLazy(config.lazy());
+                sqlFieldsQry.setLocal(config.local());
+
+                if (config.parts() != null && config.parts().length > 0)
+                    sqlFieldsQry.setPartitions(config.parts());
+
+                sqlFieldsQry.setReplicatedOnly(config.replicatedOnly());
+                sqlFieldsQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
+
+                query = sqlFieldsQry;
+            }
+            else {
+                SqlQuery sqlQry = new SqlQuery(type, queryString);
+                sqlQry.setArgs(parameters);
+
+                sqlQry.setDistributedJoins(config.distributedJoins());
+                sqlQry.setLocal(config.local());
+                if (config.parts() != null && config.parts().length > 0)
+                    sqlQry.setPartitions(config.parts());
+                sqlQry.setReplicatedOnly(config.replicatedOnly());
+                sqlQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
+
+                query = sqlQry;
             }
         }
+        else {
+
+            int pageSize = -1;
+
+            switch (qry.options()) {
+                case PAGINATION:
+                    pageSize = ((Pageable)parameters[parameters.length - 1]).getPageSize();
+                    break;
+            }
+
+            // check if queryString contains SpEL template expressions and evaluate them if any
+            if (queryString.contains("#{")) {
+                EvaluationContext queryEvalContext = queryMethodEvaluationContextProvider
+                    .getEvaluationContext(getQueryMethod().getParameters(),
+                        values);
+
+                Object eval = expressionParser.parseExpression(queryString, ParserContext.TEMPLATE_EXPRESSION)
+                    .getValue(queryEvalContext);
+
+                if (!(eval instanceof String)) {
+                    throw new IllegalStateException(
+                        "TextQuery with SpEL expressions must produce a String response, but found " + eval.getClass()
+                            .getName()
+                            + ". Please, check your expression: " + queryString);
+                }
+                queryString = (String)eval;
+            }
+
+            TextQuery textQuery = new TextQuery(type, queryString, config.limit());
+
+            textQuery.setLocal(config.local());
+
+            if (pageSize > -1)
+                textQuery.setPageSize(pageSize);
+
+            query = textQuery;
+        }
+        return query;
+    }
+
+    private static Map<String, Object> rowToMap(final List<?> row, final List<GridQueryFieldMetadata> meta) {
+        // use treemap with case insensitive property name
+        final TreeMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        for (int i = 0; i < meta.size(); i++) {
+            // don't want key or val columns
+            final String metaField = meta.get(i).fieldName().toLowerCase();
+            if (!metaField.equalsIgnoreCase(QueryUtils.KEY_FIELD_NAME) && !metaField.equalsIgnoreCase(
+                QueryUtils.VAL_FIELD_NAME))
+                map.put(metaField, row.get(i));
+        }
+        return map;
+    }
+
+    /*
+     * convert row ( with list of field values) into domain entity
+     */
+    private <V> V rowToEntity(final IgniteBinaryImpl binary,
+        final BinaryType binType,
+        final List<?> row,
+        final List<GridQueryFieldMetadata> meta) {
+        // additional data returned by query not present on domain object type
+        final TreeMap<String, Object> metadata = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        final BinaryObjectBuilder bldr = binary.builder(binType.typeName());
+
+        for (int i = 0; i < row.size(); i++) {
+            final GridQueryFieldMetadata fMeta = meta.get(i);
+            final String metaField = fMeta.fieldName();
+            // add existing entity fields to binary object
+            if (binType.field(fMeta.fieldName()) != null && !metaField.equalsIgnoreCase(QueryUtils.KEY_FIELD_NAME)
+                && !metaField.equalsIgnoreCase(QueryUtils.VAL_FIELD_NAME)) {
+                final Object fieldValue = row.get(i);
+                if (fieldValue != null) {
+                    final Class<?> clazz = getClassForBinaryField(binary, binType, fMeta);
+                    // null values must not be set into binary objects
+                    bldr.setField(metaField, fixExpectedType(fieldValue, clazz));
+                }
+            }
+            else {
+                // don't want key or val column... but wants null values
+                if (!metaField.equalsIgnoreCase(QueryUtils.KEY_FIELD_NAME) && !metaField.equalsIgnoreCase(
+                    QueryUtils.VAL_FIELD_NAME))
+                    metadata.put(metaField, row.get(i));
+            }
+        }
+        return bldr.build().deserialize();
     }
 
     /**
-     * @param prmtrs Prmtrs.
-     * @return prepared query for execution
+     * Obtains real field class from resultset metadata field whether it's available
      */
-    @SuppressWarnings("deprecation")
-    @NotNull private Query prepareQuery(Object[] prmtrs) {
-        Object[] parameters = prmtrs;
-        String sql = qry.sql();
+    private Class<?> getClassForBinaryField(final IgniteBinaryImpl binary,
+        final BinaryType binType,
+        final GridQueryFieldMetadata fieldMeta) {
+        try {
 
-        switch (qry.options()) {
-            case SORTING:
-                sql = addSorting(new StringBuilder(sql), (Sort)parameters[parameters.length - 1]).toString();
-                parameters = Arrays.copyOfRange(parameters, 0, parameters.length - 1);
+            final String fieldId = fieldMeta.schemaName() + "." + fieldMeta.typeName() + "." + fieldMeta.fieldName();
 
-                break;
+            if (binaryFieldClass.containsKey(fieldId))
+                return binaryFieldClass.get(fieldId);
 
-            case PAGINATION:
-                sql = addPaging(new StringBuilder(sql), (Pageable)parameters[parameters.length - 1]).toString();
-                parameters = Arrays.copyOfRange(parameters, 0, parameters.length - 1);
+            Class<?> clazz = null;
 
-                break;
+            synchronized (binaryFieldClass) {
 
-            case NONE:
-                // No-op.
+                if (binaryFieldClass.containsKey(fieldId))
+                    return binaryFieldClass.get(fieldId);
+
+                String fieldName = null;
+
+                // search field name on binary type (query returns case insensitive
+                // field name) but BinaryType is not case insensitive
+                for (final String fname : binType.fieldNames()) {
+                    if (fname.equalsIgnoreCase(fieldMeta.fieldName())) {
+                        fieldName = fname;
+                        break;
+                    }
+                }
+
+                final CacheObjectBinaryProcessorImpl proc = (CacheObjectBinaryProcessorImpl)binary.processor();
+
+                // search for class by typeId, if not found use
+                // fieldMeta.fieldTypeName() class
+                clazz = BinaryUtils.resolveClass(proc.binaryContext(), binary.typeId(binType.fieldTypeName(fieldName)),
+                    fieldMeta.fieldTypeName(), ignite.configuration().getClassLoader(), true);
+
+                binaryFieldClass.put(fieldId, clazz);
+            }
+
+            return clazz;
+        }
+        catch (final Exception e) {
+            return null;
         }
+    }
 
-        if (qry.isFieldQuery()) {
-            SqlFieldsQuery sqlFieldsQry = new SqlFieldsQuery(sql);
-            sqlFieldsQry.setArgs(parameters);
+    /**
+     * Validates operations that requires Pageable parameter
+     *
+     * @param returnStgy Return stgy.
+     * @param prmtrs     Prmtrs.
+     */
+    private void checkRequiredPageable(ReturnStrategy returnStgy, Object[] prmtrs) {
+        try {
+            if (returnStgy == ReturnStrategy.PAGE_OF_VALUES || returnStgy == ReturnStrategy.SLICE_OF_VALUES
+                || returnStgy == ReturnStrategy.SLICE_OF_CACHE_ENTRIES) {
+                Pageable page = (Pageable)prmtrs[prmtrs.length - 1];
+                page.isPaged();
+            }
+        }
+        catch (NullPointerException | IndexOutOfBoundsException | ClassCastException e) {
+            throw new IllegalStateException(
+                "For " + returnStgy.name() + " you must provide on last method parameter a non null Pageable instance");
+        }
+    }
 
-            return sqlFieldsQry;
+    /**
+     * @param ctx   Context.
+     * @param clazz Clazz.
+     */
+    private static void registerClassOnMarshaller(final GridKernalContext ctx, final Class<?> clazz) {
+        try {
+            // ensure class registration for marshaller on cluster...
+            if (!U.isJdk(clazz))
+                U.marshal(ctx, clazz.newInstance());
+        }
+        catch (final Exception ignored) {
+            // silent
+        }
+    }
+
+    /**
+     * Ignite QueryCursor wrapper.
+     * <p>
+     * Ensures closing underline cursor when there is no data.
+     *
+     * @param <T> input type
+     * @param <V> transformed output type
+     */
+    public static class QueryCursorWrapper<T, V> extends AbstractCollection<V> implements QueryCursor<V> {
+
+        /**
+         * Delegate query cursor.
+         */
+        private final QueryCursor<T> delegate;
+
+        /**
+         * Transformer.
+         */
+        private final Function<T, V> transformer;
+
+        /**
+         * Instantiates a new Query cursor wrapper.
+         *
+         * @param delegate    delegate QueryCursor with T input elements
+         * @param transformer Function to transform T to V elements
+         */
+        public QueryCursorWrapper(final QueryCursor<T> delegate, final Function<T, V> transformer) {
+            this.delegate = delegate;
+            this.transformer = transformer;
         }
 
-        SqlQuery sqlQry = new SqlQuery(type, sql);
-        sqlQry.setArgs(parameters);
+        /**
+         * {@inheritDoc} @return the iterator
+         */
+        @Override public Iterator<V> iterator() {
+
+            final Iterator<T> it = delegate.iterator();
+
+            return new Iterator<V>() {
+                @Override public boolean hasNext() {
+                    if (!it.hasNext()) {
+                        U.closeQuiet(delegate);
+                        return false;
+                    }
+                    return true;
+                }
+
+                @Override public V next() {
+                    final V r = transformer.apply(it.next());
+                    if (r != null)
+                        return r;
+                    throw new NoSuchElementException();
+                }
+            };
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override public void close() {
+            U.closeQuiet(delegate);
+        }
+
+        /**
+         * {@inheritDoc} @return the all
+         */
+        @Override public List<V> getAll() {
+            final List<V> data = new ArrayList<>();
+            delegate.forEach(i -> data.add(transformer.apply(i)));
+            U.closeQuiet(delegate);
+            return data;
+        }
+
+        /**
+         * {@inheritDoc} @return the int
+         */
+        @Override public int size() {
+            return 0;
+        }
 
-        return sqlQry;
     }
+
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java
new file mode 100644
index 0000000..e31c0d0
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2008-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata20.repository.query;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import org.springframework.data.util.Streamable;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import static java.util.regex.Pattern.CASE_INSENSITIVE;
+import static java.util.regex.Pattern.DOTALL;
+import static java.util.regex.Pattern.compile;
+
+/**
+ * Simple utility class to create queries.
+ *
+ * @author Oliver Gierke
+ * @author Kevin Raymond
+ * @author Thomas Darimont
+ * @author Komi Innocent
+ * @author Christoph Strobl
+ * @author Mark Paluch
+ * @author Sébastien Péralta
+ * @author Jens Schauder
+ * @author Nils Borrmann
+ * @author Reda.Housni -Alaoui
+ */
+public abstract class QueryUtils {
+    /**
+     * The constant COUNT_QUERY_STRING.
+     */
+    public static final String COUNT_QUERY_STRING = "select count(%s) from %s x";
+
+    /**
+     * The constant DELETE_ALL_QUERY_STRING.
+     */
+    public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
+
+    /**
+     * Used Regex/Unicode categories (see http://www.unicode.org/reports/tr18/#General_Category_Property): Z Separator
+     * Cc Control Cf Format P Punctuation
+     */
+    private static final String IDENTIFIER = "[._[\\P{Z}&&\\P{Cc}&&\\P{Cf}&&\\P{P}]]+";
+
+    /**
+     * The Colon no double colon.
+     */
+    static final String COLON_NO_DOUBLE_COLON = "(?<![:\\\\]):";
+
+    /**
+     * The Identifier group.
+     */
+    static final String IDENTIFIER_GROUP = String.format("(%s)", IDENTIFIER);
+
+    /** */
+    private static final String COUNT_REPLACEMENT_TEMPLATE = "select count(%s) $5$6$7";
+
+    /** */
+    private static final String SIMPLE_COUNT_VALUE = "$2";
+
+    /** */
+    private static final String COMPLEX_COUNT_VALUE = "$3$6";
+
+    /** */
+    private static final String ORDER_BY_PART = "(?iu)\\s+order\\s+by\\s+.*$";
+
+    /** */
+    private static final Pattern ALIAS_MATCH;
+
+    /** */
+    private static final Pattern COUNT_MATCH;
+
+    /** */
+    private static final Pattern PROJECTION_CLAUSE = Pattern
+        .compile("select\\s+(.+)\\s+from", Pattern.CASE_INSENSITIVE);
+
+    /** */
+    private static final String JOIN = "join\\s+(fetch\\s+)?" + IDENTIFIER + "\\s+(as\\s+)?" + IDENTIFIER_GROUP;
+
+    /** */
+    private static final Pattern JOIN_PATTERN = Pattern.compile(JOIN, Pattern.CASE_INSENSITIVE);
+
+    /** */
+    private static final String EQUALS_CONDITION_STRING = "%s.%s = :%s";
+
+    /** */
+    private static final Pattern NAMED_PARAMETER = Pattern.compile(
+        COLON_NO_DOUBLE_COLON + IDENTIFIER + "|\\#" + IDENTIFIER, CASE_INSENSITIVE);
+
+    /** */
+    private static final Pattern CONSTRUCTOR_EXPRESSION;
+
+    /** */
+    private static final int QUERY_JOIN_ALIAS_GROUP_INDEX = 3;
+
+    /** */
+    private static final int VARIABLE_NAME_GROUP_INDEX = 4;
+
+    /** */
+    private static final Pattern FUNCTION_PATTERN;
+
+    static {
+
+        StringBuilder builder = new StringBuilder();
+        builder.append("(?<=from)"); // from as starting delimiter
+        builder.append("(?:\\s)+"); // at least one space separating
+        builder.append(IDENTIFIER_GROUP); // Entity name, can be qualified (any
+        builder.append("(?:\\sas)*"); // exclude possible "as" keyword
+        builder.append("(?:\\s)+"); // at least one space separating
+        builder.append("(?!(?:where))(\\w+)"); // the actual alias
+
+        ALIAS_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
+
+        builder = new StringBuilder();
+        builder.append("(select\\s+((distinct )?(.+?)?)\\s+)?(from\\s+");
+        builder.append(IDENTIFIER);
+        builder.append("(?:\\s+as)?\\s+)");
+        builder.append(IDENTIFIER_GROUP);
+        builder.append("(.*)");
+
+        COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
+
+        builder = new StringBuilder();
+        builder.append("select");
+        builder.append("\\s+"); // at least one space separating
+        builder.append("(.*\\s+)?"); // anything in between (e.g. distinct) at least one space separating
+        builder.append("new");
+        builder.append("\\s+"); // at least one space separating
+        builder.append(IDENTIFIER);
+        builder.append("\\s*"); // zero to unlimited space separating
+        builder.append("\\(");
+        builder.append(".*");
+        builder.append("\\)");
+
+        CONSTRUCTOR_EXPRESSION = compile(builder.toString(), CASE_INSENSITIVE + DOTALL);
+
+        builder = new StringBuilder();
+        // any function call including parameters within the brackets
+        builder.append("\\w+\\s*\\([\\w\\.,\\s'=]+\\)");
+        // the potential alias
+        builder.append("\\s+[as|AS]+\\s+(([\\w\\.]+))");
+
+        FUNCTION_PATTERN = compile(builder.toString());
+    }
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private QueryUtils() {
+
+    }
+
+    /**
+     * Returns the query string to execute an exists query for the given id attributes.
+     *
+     * @param entityName        the name of the entity to create the query for, must not be {@literal null}.
+     * @param cntQryPlaceHolder the placeholder for the count clause, must not be {@literal null}.
+     * @param idAttrs           the id attributes for the entity, must not be {@literal null}.
+     * @return the exists query string
+     */
+    public static String getExistsQueryString(String entityName,
+        String cntQryPlaceHolder,
+        Iterable<String> idAttrs) {
+
+        String whereClause = Streamable.of(idAttrs).stream() //
+            .map(idAttribute -> String.format(EQUALS_CONDITION_STRING, "x", idAttribute,
+                idAttribute)) //
+            .collect(Collectors.joining(" AND ", " WHERE ", ""));
+
+        return String.format(COUNT_QUERY_STRING, cntQryPlaceHolder, entityName) + whereClause;
+    }
+
+    /**
+     * Returns the query string for the given class name.
+     *
+     * @param template   must not be {@literal null}.
+     * @param entityName must not be {@literal null}.
+     * @return the template with placeholders replaced by the {@literal entityName}. Guaranteed to be not {@literal
+     * null}.
+     */
+    public static String getQueryString(String template, String entityName) {
+
+        Assert.hasText(entityName, "Entity name must not be null or empty!");
+
+        return String.format(template, entityName);
+    }
+
+    /**
+     * Returns the aliases used for {@code left (outer) join}s.
+     *
+     * @param qry a query string to extract the aliases of joins from. Must not be {@literal null}.
+     * @return a {@literal Set} of aliases used in the query. Guaranteed to be not {@literal null}.
+     */
+    static Set<String> getOuterJoinAliases(String qry) {
+
+        Set<String> result = new HashSet<>();
+        Matcher matcher = JOIN_PATTERN.matcher(qry);
+
+        while (matcher.find()) {
+
+            String alias = matcher.group(QUERY_JOIN_ALIAS_GROUP_INDEX);
+            if (StringUtils.hasText(alias))
+                result.add(alias);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the aliases used for aggregate functions like {@code SUM, COUNT, ...}.
+     *
+     * @param qry a {@literal String} containing a query. Must not be {@literal null}.
+     * @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
+     */
+    static Set<String> getFunctionAliases(String qry) {
+
+        Set<String> result = new HashSet<>();
+        Matcher matcher = FUNCTION_PATTERN.matcher(qry);
+
+        while (matcher.find()) {
+
+            String alias = matcher.group(1);
+
+            if (StringUtils.hasText(alias))
+                result.add(alias);
+        }
+
+        return result;
+    }
+
+    /**
+     * Resolves the alias for the entity to be retrieved from the given JPA query.
+     *
+     * @param qry must not be {@literal null}.
+     * @return Might return {@literal null}.
+     * @deprecated use {@link DeclaredQuery#getAlias()} instead.
+     */
+    @Nullable
+    @Deprecated
+    public static String detectAlias(String qry) {
+
+        Matcher matcher = ALIAS_MATCH.matcher(qry);
+
+        return matcher.find() ? matcher.group(2) : null;
+    }
+
+    /**
+     * Creates a count projected query from the given original query.
+     *
+     * @param originalQry must not be {@literal null} or empty.
+     * @return Guaranteed to be not {@literal null}.
+     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
+     */
+    @Deprecated
+    public static String createCountQueryFor(String originalQry) {
+        return createCountQueryFor(originalQry, null);
+    }
+
+    /**
+     * Creates a count projected query from the given original query.
+     *
+     * @param originalQry   must not be {@literal null}.
+     * @param cntProjection may be {@literal null}.
+     * @return a query String to be used a count query for pagination. Guaranteed to be not {@literal null}.
+     * @since 1.6
+     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
+     */
+    @Deprecated
+    public static String createCountQueryFor(String originalQry, @Nullable String cntProjection) {
+
+        Assert.hasText(originalQry, "OriginalQuery must not be null or empty!");
+
+        Matcher matcher = COUNT_MATCH.matcher(originalQry);
+        String countQuery;
+
+        if (cntProjection == null) {
+
+            String variable = matcher.matches() ? matcher.group(VARIABLE_NAME_GROUP_INDEX) : null;
+            boolean useVariable = variable != null && StringUtils.hasText(variable) && !variable.startsWith("new")
+                && !variable.startsWith("count(") && !variable.contains(",");
+
+            String replacement = useVariable ? SIMPLE_COUNT_VALUE : COMPLEX_COUNT_VALUE;
+            countQuery = matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE, replacement));
+        }
+        else
+            countQuery = matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE, cntProjection));
+
+        return countQuery.replaceFirst(ORDER_BY_PART, "");
+    }
+
+    /**
+     * Returns whether the given query contains named parameters.
+     *
+     * @param qry can be {@literal null} or empty.
+     * @return whether the given query contains named parameters.
+     */
+    @Deprecated
+    static boolean hasNamedParameter(@Nullable String qry) {
+        return StringUtils.hasText(qry) && NAMED_PARAMETER.matcher(qry).find();
+    }
+
+    /**
+     * Returns whether the given JPQL query contains a constructor expression.
+     *
+     * @param qry must not be {@literal null} or empty.
+     * @return boolean
+     * @since 1.10
+     */
+    public static boolean hasConstructorExpression(String qry) {
+
+        Assert.hasText(qry, "Query must not be null or empty!");
+
+        return CONSTRUCTOR_EXPRESSION.matcher(qry).find();
+    }
+
+    /**
+     * Returns the projection part of the query, i.e. everything between {@code select} and {@code from}.
+     *
+     * @param qry must not be {@literal null} or empty.
+     * @return projection
+     * @since 1.10.2
+     */
+    public static String getProjection(String qry) {
+
+        Assert.hasText(qry, "Query must not be null or empty!");
+
+        Matcher matcher = PROJECTION_CLAUSE.matcher(qry);
+        String projection = matcher.find() ? matcher.group(1) : "";
+        return projection.trim();
+    }
+
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java
new file mode 100644
index 0000000..ca056c5
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java
@@ -0,0 +1,902 @@
+/*
+ * Copyright 2013-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata20.repository.query;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.ignite.springdata20.repository.query.spel.SpelQueryContext;
+import org.apache.ignite.springdata20.repository.query.spel.SpelQueryContext.SpelExtractor;
+import org.springframework.data.domain.Range;
+import org.springframework.data.domain.Range.Bound;
+import org.springframework.data.repository.query.parser.Part.Type;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import static java.util.regex.Pattern.CASE_INSENSITIVE;
+import static org.springframework.util.ObjectUtils.nullSafeEquals;
+import static org.springframework.util.ObjectUtils.nullSafeHashCode;
+
+/**
+ * Encapsulation of a JPA query String. Offers access to parameters as bindings. The internal query String is cleaned
+ * from decorated parameters like {@literal %:lastname%} and the matching bindings take care of applying the decorations
+ * in the {@link ParameterBinding#prepare(Object)} method. Note that this class also handles replacing SpEL expressions
+ * with synthetic bind parameters
+ *
+ * @author Oliver Gierke
+ * @author Thomas Darimont
+ * @author Oliver Wehrens
+ * @author Mark Paluch
+ * @author Jens Schauder
+ */
+class StringQuery implements DeclaredQuery {
+
+    private final String query;
+
+    private final List<ParameterBinding> bindings;
+
+    @Nullable
+    private final String alias;
+
+    private final boolean hasConstructorExpression;
+
+    private final boolean containsPageableInSpel;
+
+    private final boolean usesJdbcStyleParameters;
+
+    /**
+     * Creates a new {@link StringQuery} from the given JPQL query.
+     *
+     * @param query must not be {@literal null} or empty.
+     */
+    @SuppressWarnings("deprecation") StringQuery(String query) {
+
+        Assert.hasText(query, "Query must not be null or empty!");
+
+        bindings = new ArrayList<>();
+        containsPageableInSpel = query.contains("#pageable");
+
+        Metadata queryMeta = new Metadata();
+        this.query = ParameterBindingParser.INSTANCE
+            .parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query, bindings,
+                queryMeta);
+
+        usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
+        alias = QueryUtils.detectAlias(query);
+        hasConstructorExpression = QueryUtils.hasConstructorExpression(query);
+    }
+
+    /**
+     * Returns whether we have found some like bindings.
+     */
+    boolean hasParameterBindings() {
+        return !bindings.isEmpty();
+    }
+
+    String getProjection() {
+        return QueryUtils.getProjection(query);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getParameterBindings()
+     */
+    @Override public List<ParameterBinding> getParameterBindings() {
+        return bindings;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#deriveCountQuery(java.lang.String, java.lang
+     * .String)
+     */
+    @SuppressWarnings("deprecation")
+    @Override public DeclaredQuery deriveCountQuery(@Nullable String countQuery,
+        @Nullable String countQueryProjection) {
+
+        return DeclaredQuery
+            .of(countQuery != null ? countQuery : QueryUtils.createCountQueryFor(query, countQueryProjection));
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesJdbcStyleParameters()
+     */
+    @Override public boolean usesJdbcStyleParameters() {
+        return usesJdbcStyleParameters;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getQueryString()
+     */
+    @Override public String getQueryString() {
+        return query;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getAlias()
+     */
+    @Override @Nullable
+    public String getAlias() {
+        return alias;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasConstructorExpression()
+     */
+    @Override public boolean hasConstructorExpression() {
+        return hasConstructorExpression;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#isDefaultProjection()
+     */
+    @Override public boolean isDefaultProjection() {
+        return getProjection().equalsIgnoreCase(alias);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasNamedParameter()
+     */
+    @Override public boolean hasNamedParameter() {
+        return bindings.stream().anyMatch(b -> b.getName() != null);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesPaging()
+     */
+    @Override public boolean usesPaging() {
+        return containsPageableInSpel;
+    }
+
+    /**
+     * A parser that extracts the parameter bindings from a given query string.
+     *
+     * @author Thomas Darimont
+     */
+    enum ParameterBindingParser {
+        INSTANCE;
+        private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
+        public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
+        // .....................................................................^ not followed by a hash or a letter.
+        // .................................................................^ zero or more digits.
+        // .............................................................^ start with a question mark.
+        private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile(POSITIONAL_OR_INDEXED_PARAMETER);
+        private static final Pattern PARAMETER_BINDING_PATTERN;
+        private static final String MESSAGE =
+            "Already found parameter binding with same index / parameter name but differing binding type! "
+                + "Already have: %s, found %s! If you bind a parameter multiple times make sure they use the same "
+                + "binding.";
+        private static final int INDEXED_PARAMETER_GROUP = 4;
+        private static final int NAMED_PARAMETER_GROUP = 6;
+        private static final int COMPARISION_TYPE_GROUP = 1;
+
+        static {
+
+            List<String> keywords = new ArrayList<>();
+
+            for (ParameterBindingType type : ParameterBindingType.values()) {
+                if (type.getKeyword() != null) {
+                    keywords.add(type.getKeyword());
+                }
+            }
+
+            StringBuilder builder = new StringBuilder();
+            builder.append("(");
+            builder.append(StringUtils.collectionToDelimitedString(keywords, "|")); // keywords
+            builder.append(")?");
+            builder.append("(?: )?"); // some whitespace
+            builder.append("\\(?"); // optional braces around parameters
+            builder.append("(");
+            builder.append("%?(" + POSITIONAL_OR_INDEXED_PARAMETER + ")%?"); // position parameter and parameter index
+            builder.append("|"); // or
+
+            // named parameter and the parameter name
+            builder.append("%?(" + QueryUtils.COLON_NO_DOUBLE_COLON + QueryUtils.IDENTIFIER_GROUP + ")%?");
+
+            builder.append(")");
+            builder.append("\\)?"); // optional braces around parameters
+
+            PARAMETER_BINDING_PATTERN = Pattern.compile(builder.toString(), CASE_INSENSITIVE);
+        }
+
+        /**
+         * Parses {@link ParameterBinding} instances from the given query and adds them to the registered bindings.
+         * Returns the cleaned up query.
+         */
+        private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String query,
+            List<ParameterBinding> bindings,
+            Metadata queryMeta) {
+
+            int greatestParamIdx = tryFindGreatestParameterIndexIn(query);
+            boolean parametersShouldBeAccessedByIdx = greatestParamIdx != -1;
+
+            /*
+             * Prefer indexed access over named parameters if only SpEL Expression parameters are present.
+             */
+            if (!parametersShouldBeAccessedByIdx && query.contains("?#{")) {
+                parametersShouldBeAccessedByIdx = true;
+                greatestParamIdx = 0;
+            }
+
+            SpelExtractor spelExtractor = createSpelExtractor(query, parametersShouldBeAccessedByIdx,
+                greatestParamIdx);
+
+            String resultingQry = spelExtractor.getQueryString();
+            Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(resultingQry);
+            QuotationMap quotedAreas = new QuotationMap(resultingQry);
+
+            int expressionParamIdx = parametersShouldBeAccessedByIdx ? greatestParamIdx : 0;
+
+            boolean usesJpaStyleParameters = false;
+            while (matcher.find()) {
+
+                if (quotedAreas.isQuoted(matcher.start()))
+                    continue;
+
+                String paramIdxStr = matcher.group(INDEXED_PARAMETER_GROUP);
+                String paramName = paramIdxStr != null ? null : matcher.group(NAMED_PARAMETER_GROUP);
+                Integer paramIdx = getParameterIndex(paramIdxStr);
+
+                String typeSrc = matcher.group(COMPARISION_TYPE_GROUP);
+                String expression = spelExtractor
+                    .getParameter(paramName == null ? paramIdxStr : paramName);
+                String replacement = null;
+
+                Assert.isTrue(paramIdxStr != null || paramName != null,
+                    () -> String.format("We need either a name or an index! Offending query string: %s", query));
+
+                expressionParamIdx++;
+                if (paramIdxStr != null && paramIdxStr.isEmpty()) {
+
+                    queryMeta.usesJdbcStyleParameters = true;
+                    paramIdx = expressionParamIdx;
+                }
+                else
+                    usesJpaStyleParameters = true;
+
+                // named parameters (:param) will be untouched by spelExtractor, so replace them by ? as we don't
+                // know position
+                if (paramName != null)
+                    replacement = "?";
+
+                if (usesJpaStyleParameters && queryMeta.usesJdbcStyleParameters) {
+                    throw new IllegalArgumentException(
+                        "Mixing of ? (? or :myNamedParam) parameters and other forms like ?1 (SpEL espressions or "
+                            + "indexed) is not supported!. Please, if you are using expressions or "
+                            + "indexed params, replace all named parameters by expressions. Example :myNamedParam "
+                            + "by ?#{#myNamedParam}.");
+                }
+
+                switch (ParameterBindingType.of(typeSrc)) {
+
+                    case LIKE:
+
+                        Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2));
+                        replacement = matcher.group(3);
+
+                        if (paramIdx != null)
+                            checkAndRegister(new LikeParameterBinding(paramIdx, likeType, expression), bindings);
+                        else {
+                            checkAndRegister(new LikeParameterBinding(paramName, likeType, expression), bindings);
+
+                            replacement = expression != null ? ":" + paramName : matcher.group(5);
+                        }
+
+                        break;
+
+                    case IN:
+
+                        if (paramIdx != null)
+                            checkAndRegister(new InParameterBinding(paramIdx, expression), bindings);
+                        else
+                            checkAndRegister(new InParameterBinding(paramName, expression), bindings);
+
+                        break;
+
+                    case AS_IS: // fall-through we don't need a special parameter binding for the given parameter.
+                    default:
+                        bindings.add(paramIdx != null
+                            ? new ParameterBinding(null, paramIdx, expression)
+                            : new ParameterBinding(paramName, null, expression));
+                }
+
+                if (replacement != null)
+                    resultingQry = replaceFirst(resultingQry, matcher.group(2), replacement);
+            }
+
+            return resultingQry;
+        }
+
+        private static SpelExtractor createSpelExtractor(String queryWithSpel,
+            boolean parametersShouldBeAccessedByIndex,
+            int greatestParameterIndex) {
+
+            /*
+             * If parameters need to be bound by index, we bind the synthetic expression parameters starting from
+             * position of the greatest discovered index parameter in order to
+             * not mix-up with the actual parameter indices.
+             */
+            int expressionParameterIndex = parametersShouldBeAccessedByIndex ? greatestParameterIndex : 0;
+
+            BiFunction<Integer, String, String> indexToParameterName = parametersShouldBeAccessedByIndex
+                ? (index, expression) -> String.valueOf(
+                index + expressionParameterIndex + 1)
+                : (index, expression) ->
+                EXPRESSION_PARAMETER_PREFIX + (index
+                    + 1);
+
+            String fixedPrefix = parametersShouldBeAccessedByIndex ? "?" : ":";
+
+            BiFunction<String, String, String> parameterNameToReplacement = (prefix, name) -> fixedPrefix + name;
+
+            return SpelQueryContext.of(indexToParameterName, parameterNameToReplacement).parse(queryWithSpel);
+        }
+
+        private static String replaceFirst(String text, String substring, String replacement) {
+
+            int index = text.indexOf(substring);
+            if (index < 0)
+                return text;
+
+            return text.substring(0, index) + replacement + text.substring(index + substring.length());
+        }
+
+        @Nullable
+        private static Integer getParameterIndex(@Nullable String parameterIndexString) {
+
+            if (parameterIndexString == null || parameterIndexString.isEmpty())
+                return null;
+            return Integer.valueOf(parameterIndexString);
+        }
+
+        private static int tryFindGreatestParameterIndexIn(String query) {
+
+            Matcher parameterIndexMatcher = PARAMETER_BINDING_BY_INDEX.matcher(query);
+
+            int greatestParameterIndex = -1;
+            while (parameterIndexMatcher.find()) {
+
+                String parameterIndexString = parameterIndexMatcher.group(1);
+                Integer parameterIndex = getParameterIndex(parameterIndexString);
+                if (parameterIndex != null)
+                    greatestParameterIndex = Math.max(greatestParameterIndex, parameterIndex);
+            }
+
+            return greatestParameterIndex;
+        }
+
+        private static void checkAndRegister(ParameterBinding binding, List<ParameterBinding> bindings) {
+
+            bindings.stream() //
+                .filter(it -> it.hasName(binding.getName()) || it.hasPosition(binding.getPosition())) //
+                .forEach(it -> Assert.isTrue(it.equals(binding), String.format(MESSAGE, it, binding)));
+
+            if (!bindings.contains(binding))
+                bindings.add(binding);
+        }
+
+        /**
+         * An enum for the different types of bindings.
+         *
+         * @author Thomas Darimont
+         * @author Oliver Gierke
+         */
+        private enum ParameterBindingType {
+            // Trailing whitespace is intentional to reflect that the keywords must be used with at least one whitespace
+            // character, while = does not.
+            LIKE("like "),
+            IN("in "),
+            AS_IS(null);
+            private final @Nullable
+            String keyword;
+
+            ParameterBindingType(@Nullable String keyword) {
+                this.keyword = keyword;
+            }
+
+            /**
+             * Returns the keyword that will tirgger the binding type or {@literal null} if the type is not triggered by
+             * a keyword.
+             *
+             * @return the keyword
+             */
+            @Nullable
+            public String getKeyword() {
+                return keyword;
+            }
+
+            /**
+             * Return the appropriate {@link ParameterBindingType} for the given {@link String}. Returns {@literal
+             * #AS_IS} in case no other {@link ParameterBindingType} could be found.
+             */
+            static ParameterBindingType of(String typeSource) {
+
+                if (!StringUtils.hasText(typeSource))
+                    return AS_IS;
+
+                for (ParameterBindingType type : values()) {
+                    if (type.name().equalsIgnoreCase(typeSource.trim()))
+                        return type;
+                }
+
+                throw new IllegalArgumentException(String.format("Unsupported parameter binding type %s!", typeSource));
+            }
+        }
+    }
+
+    /**
+     * A generic parameter binding with name or position information.
+     *
+     * @author Thomas Darimont
+     */
+    static class ParameterBinding {
+        @Nullable
+        private final String name;
+
+        @Nullable
+        private final String expression;
+
+        @Nullable
+        private final Integer position;
+
+        /**
+         * Creates a new {@link ParameterBinding} for the parameter with the given position.
+         *
+         * @param position must not be {@literal null}.
+         */
+        ParameterBinding(Integer position) {
+            this(null, position, null);
+        }
+
+        /**
+         * Creates a new {@link ParameterBinding} for the parameter with the given name, position and expression
+         * information. Either {@literal name} or {@literal position} must be not {@literal null}.
+         *
+         * @param name       of the parameter may be {@literal null}.
+         * @param position   of the parameter may be {@literal null}.
+         * @param expression the expression to apply to any value for this parameter.
+         */
+        ParameterBinding(@Nullable String name, @Nullable Integer position, @Nullable String expression) {
+
+            if (name == null)
+                Assert.notNull(position, "Position must not be null!");
+
+            if (position == null)
+                Assert.notNull(name, "Name must not be null!");
+
+            this.name = name;
+            this.position = position;
+            this.expression = expression;
+        }
+
+        /**
+         * Returns whether the binding has the given name. Will always be {@literal false} in case the {@link
+         * ParameterBinding} has been set up from a position.
+         */
+        boolean hasName(@Nullable String name) {
+            return position == null && this.name != null && this.name.equals(name);
+        }
+
+        /**
+         * Returns whether the binding has the given position. Will always be {@literal false} in case the {@link
+         * ParameterBinding} has been set up from a name.
+         */
+        boolean hasPosition(@Nullable Integer position) {
+            return position != null && name == null && position.equals(this.position);
+        }
+
+        /**
+         * @return the name
+         */
+        @Nullable
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @return the name
+         * @throws IllegalStateException if the name is not available.
+         * @since 2.0
+         */
+        String getRequiredName() throws IllegalStateException {
+
+            String name = getName();
+
+            if (name != null)
+                return name;
+
+            throw new IllegalStateException(String.format("Required name for %s not available!", this));
+        }
+
+        /**
+         * @return the position
+         */
+        @Nullable
+        Integer getPosition() {
+            return position;
+        }
+
+        /**
+         * @return the position
+         * @throws IllegalStateException if the position is not available.
+         * @since 2.0
+         */
+        int getRequiredPosition() throws IllegalStateException {
+
+            Integer position = getPosition();
+
+            if (position != null)
+                return position;
+
+            throw new IllegalStateException(String.format("Required position for %s not available!", this));
+        }
+
+        /**
+         * @return {@literal true} if this parameter binding is a synthetic SpEL expression.
+         */
+        public boolean isExpression() {
+            return expression != null;
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override public int hashCode() {
+
+            int result = 17;
+
+            result += nullSafeHashCode(name);
+            result += nullSafeHashCode(position);
+            result += nullSafeHashCode(expression);
+
+            return result;
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override public boolean equals(Object obj) {
+
+            if (!(obj instanceof ParameterBinding))
+                return false;
+
+            ParameterBinding that = (ParameterBinding)obj;
+
+            return nullSafeEquals(name, that.name) && nullSafeEquals(position, that.position)
+                && nullSafeEquals(expression, that.expression);
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see java.lang.Object#toString()
+         */
+        @Override public String toString() {
+            return String.format("ParameterBinding [name: %s, position: %d, expression: %s]", getName(), getPosition(),
+                getExpression());
+        }
+
+        /**
+         * @param valueToBind value to prepare
+         */
+        @Nullable
+        public Object prepare(@Nullable Object valueToBind) {
+            return valueToBind;
+        }
+
+        @Nullable
+        public String getExpression() {
+            return expression;
+        }
+
+    }
+
+    /**
+     * Represents a {@link ParameterBinding} in a JPQL query augmented with instructions of how to apply a parameter as
+     * an {@code IN} parameter.
+     *
+     * @author Thomas Darimont
+     */
+    static class InParameterBinding extends ParameterBinding {
+
+        /**
+         * Creates a new {@link InParameterBinding} for the parameter with the given name.
+         */
+        InParameterBinding(String name, @Nullable String expression) {
+            super(name, null, expression);
+        }
+
+        /**
+         * Creates a new {@link InParameterBinding} for the parameter with the given position.
+         */
+        InParameterBinding(int position, @Nullable String expression) {
+            super(null, position, expression);
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding#prepare(java.lang.Object)
+         */
+        @Override public Object prepare(@Nullable Object value) {
+
+            if (!ObjectUtils.isArray(value))
+                return value;
+
+            int length = Array.getLength(value);
+            Collection<Object> result = new ArrayList<>(length);
+
+            for (int i = 0; i < length; i++)
+                result.add(Array.get(value, i));
+
+            return result;
+        }
+
+    }
+
+    /**
+     * Represents a parameter binding in a JPQL query augmented with instructions of how to apply a parameter as LIKE
+     * parameter. This allows expressions like {@code …like %?1} in the JPQL query, which is not allowed by plain JPA.
+     *
+     * @author Oliver Gierke
+     * @author Thomas Darimont
+     */
+    static class LikeParameterBinding extends ParameterBinding {
+
+        private static final List<Type> SUPPORTED_TYPES = Arrays.asList(Type.CONTAINING, Type.STARTING_WITH,
+            Type.ENDING_WITH, Type.LIKE);
+
+        private final Type type;
+
+        /**
+         * Creates a new {@link LikeParameterBinding} for the parameter with the given name and {@link Type}.
+         *
+         * @param name must not be {@literal null} or empty.
+         * @param type must not be {@literal null}.
+         */
+        LikeParameterBinding(String name, Type type) {
+            this(name, type, null);
+        }
+
+        /**
+         * Creates a new {@link LikeParameterBinding} for the parameter with the given name and {@link Type} and
+         * parameter binding input.
+         *
+         * @param name       must not be {@literal null} or empty.
+         * @param type       must not be {@literal null}.
+         * @param expression may be {@literal null}.
+         */
+        LikeParameterBinding(String name, Type type, @Nullable String expression) {
+
+            super(name, null, expression);
+
+            Assert.hasText(name, "Name must not be null or empty!");
+            Assert.notNull(type, "Type must not be null!");
+
+            Assert.isTrue(SUPPORTED_TYPES.contains(type), String.format("Type must be one of %s!",
+                StringUtils.collectionToCommaDelimitedString(SUPPORTED_TYPES)));
+
+            this.type = type;
+        }
+
+        /**
+         * Creates a new {@link LikeParameterBinding} for the parameter with the given position and {@link Type}.
+         *
+         * @param position position of the parameter in the query.
+         * @param type     must not be {@literal null}.
+         */
+        LikeParameterBinding(int position, Type type) {
+            this(position, type, null);
+        }
+
+        /**
+         * Creates a new {@link LikeParameterBinding} for the parameter with the given position and {@link Type}.
+         *
+         * @param position   position of the parameter in the query.
+         * @param type       must not be {@literal null}.
+         * @param expression may be {@literal null}.
+         */
+        LikeParameterBinding(int position, Type type, @Nullable String expression) {
+
+            super(null, position, expression);
+
+            Assert.isTrue(position > 0, "Position must be greater than zero!");
+            Assert.notNull(type, "Type must not be null!");
+
+            Assert.isTrue(SUPPORTED_TYPES.contains(type), String.format("Type must be one of %s!",
+                StringUtils.collectionToCommaDelimitedString(SUPPORTED_TYPES)));
+
+            this.type = type;
+        }
+
+        /**
+         * Returns the {@link Type} of the binding.
+         *
+         * @return the type
+         */
+        public Type getType() {
+            return type;
+        }
+
+        /**
+         * Prepares the given raw keyword according to the like type.
+         */
+        @Nullable
+        @Override public Object prepare(@Nullable Object value) {
+
+            if (value == null)
+                return null;
+
+            switch (type) {
+                case STARTING_WITH:
+                    return String.format("%s%%", value.toString());
+                case ENDING_WITH:
+                    return String.format("%%%s", value.toString());
+                case CONTAINING:
+                    return String.format("%%%s%%", value.toString());
+                case LIKE:
+                default:
+                    return value;
+            }
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override public boolean equals(Object obj) {
+
+            if (!(obj instanceof LikeParameterBinding))
+                return false;
+
+            LikeParameterBinding that = (LikeParameterBinding)obj;
+
+            return super.equals(obj) && type.equals(that.type);
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override public int hashCode() {
+
+            int result = super.hashCode();
+
+            result += nullSafeHashCode(type);
+
+            return result;
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see java.lang.Object#toString()
+         */
+        @Override public String toString() {
+            return String.format("LikeBinding [name: %s, position: %d, type: %s]", getName(), getPosition(), type);
+        }
+
+        /**
+         * Extracts the like {@link Type} from the given JPA like expression.
+         *
+         * @param expression must not be {@literal null} or empty.
+         */
+        private static Type getLikeTypeFrom(String expression) {
+
+            Assert.hasText(expression, "Expression must not be null or empty!");
+
+            if (expression.matches("%.*%"))
+                return Type.CONTAINING;
+
+            if (expression.startsWith("%"))
+                return Type.ENDING_WITH;
+
+            if (expression.endsWith("%"))
+                return Type.STARTING_WITH;
+
+            return Type.LIKE;
+        }
+
+    }
+
+    static class Metadata {
+
+        /**
+         * Uses jdbc style parameters.
+         */
+        private boolean usesJdbcStyleParameters;
+
+    }
+
+    /**
+     * Value object to analyze a {@link String} to determine the parts of the {@link String} that are quoted and offers
+     * an API to query that information.
+     *
+     * @author Jens Schauder
+     * @author Oliver Gierke
+     * @since 2.1
+     */
+    static class QuotationMap {
+
+        private static final Collection<Character> QUOTING_CHARACTERS = Arrays.asList('"', '\'');
+
+        private final List<Range<Integer>> quotedRanges = new ArrayList<>();
+
+        /**
+         * Creates a new instance for the query.
+         *
+         * @param query can be {@literal null}.
+         */
+        public QuotationMap(@Nullable String query) {
+
+            if (query == null)
+                return;
+
+            Character inQuotation = null;
+            int start = 0;
+
+            for (int i = 0; i < query.length(); i++) {
+
+                char currentChar = query.charAt(i);
+
+                if (QUOTING_CHARACTERS.contains(currentChar)) {
+
+                    if (inQuotation == null) {
+
+                        inQuotation = currentChar;
+                        start = i;
+                    }
+                    else if (currentChar == inQuotation) {
+
+                        inQuotation = null;
+
+                        quotedRanges.add(Range.from(Bound.inclusive(start)).to(Bound.inclusive(i)));
+                    }
+                }
+            }
+
+            if (inQuotation != null) {
+                throw new IllegalArgumentException(
+                    String.format("The string <%s> starts a quoted range at %d, but never ends it.", query, start));
+            }
+        }
+
+        /**
+         * Checks if a given index is within a quoted range.
+         *
+         * @param idx to check if it is part of a quoted range.
+         * @return whether the query contains a quoted range at {@literal index}.
+         */
+        public boolean isQuoted(int idx) {
+            return quotedRanges.stream().anyMatch(r -> r.contains(idx));
+        }
+
+    }
+
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java
new file mode 100644
index 0000000..f2b5e26
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018-2019 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 org.apache.ignite.springdata20.repository.query.spel;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.springdata20.repository.query.spel.SpelQueryContext.SpelExtractor;
+import org.springframework.data.repository.query.EvaluationContextProvider;
+import org.springframework.data.repository.query.Parameters;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * Evaluates SpEL expressions as extracted by the {@link SpelExtractor} based on parameter information from a method and
+ * parameter values from a method call.
+ *
+ * @author Jens Schauder
+ * @author Gerrit Meier
+ * @author Oliver Gierke
+ * @since spring data 2.1 - transition code (borrowed and adapted code from version 2.1)
+ */
+public class SpelEvaluator {
+    /**
+     * Parser.
+     */
+    private static final SpelExpressionParser PARSER = new SpelExpressionParser();
+
+    /**
+     * Evaluation context provider.
+     */
+    private final EvaluationContextProvider evaluationCtxProvider;
+
+    /**
+     * Parameters.
+     */
+    private final Parameters<?, ?> parameters;
+
+    /**
+     * Extractor.
+     */
+    private final SpelExtractor extractor;
+
+    /**
+     * @param evaluationCtxProvider Evaluation context provider.
+     * @param parameters            Parameters.
+     * @param extractor             Extractor.
+     */
+    public SpelEvaluator(EvaluationContextProvider evaluationCtxProvider,
+        Parameters<?, ?> parameters,
+        SpelExtractor extractor) {
+        this.evaluationCtxProvider = evaluationCtxProvider;
+        this.parameters = parameters;
+        this.extractor = extractor;
+    }
+
+    /**
+     * Evaluate all the SpEL expressions in {@link #parameters} based on values provided as an argument.
+     *
+     * @param values Parameter values. Must not be {@literal null}.
+     * @return a map from parameter name to evaluated value. Guaranteed to be not {@literal null}.
+     */
+    public Map<String, Object> evaluate(Object[] values) {
+
+        Assert.notNull(values, "Values must not be null.");
+
+        EvaluationContext evaluationCtx = evaluationCtxProvider.getEvaluationContext(parameters, values);
+
+        return extractor.getParameters().collect(Collectors.toMap(//
+            Map.Entry::getKey, //
+            it -> getSpElValue(evaluationCtx, it.getValue()) //
+        ));
+    }
+
+    /**
+     * Returns the query string produced by the intermediate SpEL expression collection step.
+     *
+     * @return the query string produced by the intermediate SpEL expression collection step
+     */
+    public String getQueryString() {
+        return extractor.getQueryString();
+    }
+
+    /**
+     * @param evaluationCtx Evaluation context.
+     * @param expression    Expression.
+     */
+    @Nullable
+    private static Object getSpElValue(EvaluationContext evaluationCtx, String expression) {
+        return PARSER.parseExpression(expression).getValue(evaluationCtx);
+    }
+
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java
new file mode 100644
index 0000000..579b36f
--- /dev/null
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2018-2019 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 org.apache.ignite.springdata20.repository.query.spel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.BiFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import org.springframework.data.domain.Range;
+import org.springframework.data.domain.Range.Bound;
+import org.springframework.data.repository.query.EvaluationContextProvider;
+import org.springframework.data.repository.query.Parameters;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * Source of {@link SpelExtractor} encapsulating configuration often common for all queries.
+ *
+ * @author Jens Schauder
+ * @author Gerrit Meier
+ * @since spring data 2.1 - transition code (borrowed and adapted code from version 2.1)
+ */
+public class SpelQueryContext {
+    /**
+     * Spel pattern string.
+     */
+    private static final String SPEL_PATTERN_STRING = "([:?])#\\{([^}]+)}";
+
+    /**
+     * Spel pattern.
+     */
+    private static final Pattern SPEL_PATTERN = Pattern.compile(SPEL_PATTERN_STRING);
+
+    /**
+     * A function from the index of a SpEL expression in a query and the actual SpEL expression to the parameter name to
+     * be used in place of the SpEL expression. A typical implementation is expected to look like
+     * <code>(index, spel) -> "__some_placeholder_" + index</code>
+     */
+    private final BiFunction<Integer, String, String> paramNameSrc;
+
+    /**
+     * A function from a prefix used to demarcate a SpEL expression in a query and a parameter name as returned from
+     * {@link #paramNameSrc} to a {@literal String} to be used as a replacement of the SpEL in the query. The returned
+     * value should normally be interpretable as a bind parameter by the underlying persistence mechanism. A typical
+     * implementation is expected to look like <code>(prefix, name) -> prefix + name</code> or
+     * <code>(prefix, name) -> "{" + name + "}"</code>
+     */
+    private final BiFunction<String, String, String> replacementSrc;
+
+    private SpelQueryContext(BiFunction<Integer, String, String> paramNameSrc,
+        BiFunction<String, String, String> replacementSrc) {
+        this.paramNameSrc = paramNameSrc;
+        this.replacementSrc = replacementSrc;
+    }
+
+    /**
+     * Of spel query context.
+     *
+     * @param parameterNameSource the parameter name source
+     * @param replacementSource   the replacement source
+     * @return the spel query context
+     */
+    public static SpelQueryContext of(BiFunction<Integer, String, String> parameterNameSource,
+        BiFunction<String, String, String> replacementSource) {
+        return new SpelQueryContext(parameterNameSource, replacementSource);
+    }
+
+    /**
+     * Parses the query for SpEL expressions using the pattern:
+     *
+     * <pre>
+     * &lt;prefix&gt;#{&lt;spel&gt;}
+     * </pre>
+     * <p>
+     * with prefix being the character ':' or '?'. Parsing honors quoted {@literal String}s enclosed in single or double
+     * quotation marks.
+     *
+     * @param qry a query containing SpEL expressions in the format described above. Must not be {@literal null}.
+     * @return A {@link SpelExtractor} which makes the query with SpEL expressions replaced by bind parameters and a map
+     * from bind parameter to SpEL expression available. Guaranteed to be not {@literal null}.
+     */
+    public SpelExtractor parse(String qry) {
+        return new SpelExtractor(qry);
+    }
+
+    /**
+     * Createsa {@link EvaluatingSpelQueryContext} from the current one and the given {@link
+     * EvaluationContextProvider}*.
+     *
+     * @param provider must not be {@literal null}.
+     * @return Evaluating Spel QueryContext
+     */
+    public EvaluatingSpelQueryContext withEvaluationContextProvider(EvaluationContextProvider provider) {
+
+        Assert.notNull(provider, "EvaluationContextProvider must not be null!");
+
+        return new EvaluatingSpelQueryContext(provider, paramNameSrc, replacementSrc);
+    }
+
+    /**
+     * An extension of {@link SpelQueryContext} that can create {@link SpelEvaluator} instances as it also knows about a
+     * {@link EvaluationContextProvider}.
+     *
+     * @author Oliver Gierke
+     * @since 2.1
+     */
+    public static class EvaluatingSpelQueryContext extends SpelQueryContext {
+
+        private final EvaluationContextProvider evaluationContextProvider;
+
+        /**
+         * Creates a new {@link EvaluatingSpelQueryContext} for the given {@link EvaluationContextProvider}, parameter
+         * name source and replacement source.
+         *
+         * @param evaluationCtxProvider must not be {@literal null}.
+         * @param paramNameSrc          must not be {@literal null}.
+         * @param replacementSrc        must not be {@literal null}.
+         */
+        private EvaluatingSpelQueryContext(EvaluationContextProvider evaluationCtxProvider,
+            BiFunction<Integer, String, String> paramNameSrc, BiFunction<String, String, String> replacementSrc) {
+
+            super(paramNameSrc, replacementSrc);
+
+            evaluationContextProvider = evaluationCtxProvider;
+        }
+
+        /**
+         * Parses the query for SpEL expressions using the pattern:
+         *
+         * <pre>
+         * &lt;prefix&gt;#{&lt;spel&gt;}
+         * </pre>
+         * <p>
+         * with prefix being the character ':' or '?'. Parsing honors quoted {@literal String}s enclosed in single or
+         * double quotation marks.
+         *
+         * @param qry        a query containing SpEL expressions in the format described above. Must not be {@literal
+         *                   null}.
+         * @param parameters a {@link Parameters} instance describing query method parameters
+         * @return A {@link SpelEvaluator} which allows to evaluate the SpEL expressions. Will never be {@literal null}.
+         */
+        public SpelEvaluator parse(String qry, Parameters<?, ?> parameters) {
+            return new SpelEvaluator(evaluationContextProvider, parameters, parse(qry));
+        }
+    }
+
+    /**
+     * Parses a query string, identifies the contained SpEL expressions, replaces them with bind parameters and offers a
+     * {@link Map} from those bind parameters to the spel expression.
+     * <p>
+     * The parser detects quoted parts of the query string and does not detect SpEL expressions inside such quoted parts
+     * of the query.
+     *
+     * @author Jens Schauder
+     * @author Oliver Gierke
+     * @since 2.1
+     */
+    public class SpelExtractor {
+
+        /**
+         * Prefix group index.
+         */
+        private static final int PREFIX_GROUP_INDEX = 1;
+
+        /**
+         * Expression group index.
+         */
+        private static final int EXPRESSION_GROUP_INDEX = 2;
+
+        /**
+         * Query.
+         */
+        private final String query;
+
+        /**
+         * Expressions.
+         */
+        private final Map<String, String> expressions;
+
+        /**
+         * Quotations.
+         */
+        private final QuotationMap quotations;
+
+        /**
+         * Creates a SpelExtractor from a query String.
+         *
+         * @param qry must not be {@literal null}.
+         */
+        SpelExtractor(String qry) {
+
+            Assert.notNull(qry, "Query must not be null");
+
+            Map<String, String> exps = new HashMap<>();
+            Matcher matcher = SPEL_PATTERN.matcher(qry);
+            StringBuilder resultQry = new StringBuilder();
+            QuotationMap quotedAreas = new QuotationMap(qry);
+
+            int expressionCounter = 0;
+            int matchedUntil = 0;
+
+            while (matcher.find()) {
+
+                if (quotedAreas.isQuoted(matcher.start()))
+                    resultQry.append(qry, matchedUntil, matcher.end());
+                else {
+
+                    String spelExpression = matcher.group(EXPRESSION_GROUP_INDEX);
+                    String prefix = matcher.group(PREFIX_GROUP_INDEX);
+
+                    String paramName = paramNameSrc.apply(expressionCounter, spelExpression);
+                    String replacement = replacementSrc.apply(prefix, paramName);
+
+                    resultQry.append(qry, matchedUntil, matcher.start());
+                    resultQry.append(replacement);
+
+                    exps.put(paramName, spelExpression);
+                    expressionCounter++;
+                }
+
+                matchedUntil = matcher.end();
+            }
+
+            resultQry.append(qry.substring(matchedUntil));
+
+            expressions = Collections.unmodifiableMap(exps);
+            query = resultQry.toString();
+            quotations = quotedAreas;
+        }
+
+        /**
+         * The query with all the SpEL expressions replaced with bind parameters.
+         *
+         * @return Guaranteed to be not {@literal null}.
+         */
+        public String getQueryString() {
+            return query;
+        }
+
+        /**
+         * Is quoted.
+         *
+         * @param idx the idx
+         * @return the boolean
+         */
+        public boolean isQuoted(int idx) {
+            return quotations.isQuoted(idx);
+        }
+
+        /**
+         * Gets parameter.
+         *
+         * @param name the name
+         * @return the parameter
+         */
+        public String getParameter(String name) {
+            return expressions.get(name);
+        }
+
+        /**
+         * A {@literal Map} from parameter name to SpEL expression.
+         *
+         * @return Guaranteed to be not {@literal null}.
+         */
+        Map<String, String> getParameterMap() {
+            return expressions;
+        }
+
+        /**
+         * Gets parameters.
+         *
+         * @return the parameters
+         */
+        Stream<Entry<String, String>> getParameters() {
+            return expressions.entrySet().stream();
+        }
+    }
+
+    /**
+     * Value object to analyze a {@link String} to determine the parts of the {@link String} that are quoted and offers
+     * an API to query that information.
+     *
+     * @author Jens Schauder
+     * @author Oliver Gierke
+     * @since 2.1
+     */
+    static class QuotationMap {
+
+        /**
+         * Quoting characters.
+         */
+        private static final Collection<Character> QUOTING_CHARACTERS = Arrays.asList('"', '\'');
+
+        /**
+         * Quoted ranges.
+         */
+        private final List<Range<Integer>> quotedRanges = new ArrayList<>();
+
+        /**
+         * Creates a new {@link QuotationMap} for the query.
+         *
+         * @param qry can be {@literal null}.
+         */
+        public QuotationMap(@Nullable String qry) {
+
+            if (qry == null)
+                return;
+
+            Character inQuotation = null;
+            int start = 0;
+
+            for (int i = 0; i < qry.length(); i++) {
+
+                char curChar = qry.charAt(i);
+
+                if (QUOTING_CHARACTERS.contains(curChar)) {
+
+                    if (inQuotation == null) {
+
+                        inQuotation = curChar;
+                        start = i;
+
+                    }
+                    else if (curChar == inQuotation) {
+
+                        inQuotation = null;
+
+                        quotedRanges.add(Range.from(Bound.inclusive(start)).to(Bound.inclusive(i)));
+                    }
+                }
+            }
+
+            if (inQuotation != null) {
+                throw new IllegalArgumentException(
+                    String.format("The string <%s> starts a quoted range at %d, but never ends it.", qry, start));
+            }
+        }
+
+        /**
+         * Checks if a given index is within a quoted range.
+         *
+         * @param idx to check if it is part of a quoted range.
+         * @return whether the query contains a quoted range at {@literal index}.
+         */
+        public boolean isQuoted(int idx) {
+            return quotedRanges.stream().anyMatch(r -> r.contains(idx));
+        }
+    }
+}
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java
index daeacf5..f77f220 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java
@@ -22,11 +22,12 @@ import org.springframework.context.annotation.ConditionContext;
 import org.springframework.core.type.AnnotatedTypeMetadata;
 
 /**
- * Always false condition.
- * Tells spring context never load bean with such Condition.
+ * Always false condition. Tells spring context never load bean with such Condition.
  */
 public class ConditionFalse implements Condition {
-    /**{@inheritDoc}*/
+    /**
+     * {@inheritDoc}
+     */
     @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
         return false;
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
index 3382c8a..be83460 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
@@ -20,15 +20,19 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.springdata20.repository.IgniteRepository;
+import org.apache.ignite.springdata20.repository.config.DynamicQueryConfig;
 import org.apache.ignite.springdata20.repository.config.Query;
 import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
 import org.apache.ignite.springdata20.repository.query.IgniteQuery;
 import org.apache.ignite.springdata20.repository.query.IgniteQueryGenerator;
 import org.apache.ignite.springdata20.repository.query.IgniteRepositoryQuery;
 import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanExpressionContext;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.context.ApplicationContext;
@@ -45,74 +49,99 @@ import org.springframework.util.StringUtils;
 
 /**
  * Crucial for spring-data functionality class. Create proxies for repositories.
+ * <p>
+ * Supports multiple Ignite Instances on same JVM.
+ * <p>
+ * This is pretty useful working with Spring repositories bound to different Ignite intances within same application.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteRepositoryFactory extends RepositoryFactorySupport {
-    /** Ignite instance */
-    private Ignite ignite;
-
-    /** Spring application context */
-    private ApplicationContext ctx;
+    /**
+     * Spring application context
+     */
+    private final ApplicationContext ctx;
 
-    /** Spring application bean factory */
-    private DefaultListableBeanFactory beanFactory;
+    /**
+     * Spring application bean factory
+     */
+    private final DefaultListableBeanFactory beanFactory;
 
-    /** Spring application expression resolver */
-    private StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
+    /**
+     * Spring application expression resolver
+     */
+    private final StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
 
-    /** Spring application bean expression context */
-    private BeanExpressionContext beanExpressionContext;
+    /**
+     * Spring application bean expression context
+     */
+    private final BeanExpressionContext beanExpressionContext;
 
-    /** Mapping of a repository to a cache. */
+    /**
+     * Mapping of a repository to a cache.
+     */
     private final Map<Class<?>, String> repoToCache = new HashMap<>();
 
     /**
-     * Creates the factory with initialized {@link Ignite} instance.
-     *
-     * @param ignite
+     * Mapping of a repository to a ignite instance.
      */
-    public IgniteRepositoryFactory(Ignite ignite, ApplicationContext ctx) {
-        this.ignite = ignite;
-
-        this.ctx = ctx;
-
-        this.beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
-
-        this.beanExpressionContext = new BeanExpressionContext(beanFactory, null);
-    }
+    private final Map<Class<?>, Ignite> repoToIgnite = new HashMap<>();
 
     /**
-     * Initializes the factory with provided {@link IgniteConfiguration} that is used to start up an underlying
-     * {@link Ignite} instance.
+     * Creates the factory with initialized {@link Ignite} instance.
      *
-     * @param cfg Ignite configuration.
+     * @param ctx the ctx
      */
-    public IgniteRepositoryFactory(IgniteConfiguration cfg, ApplicationContext ctx) {
-        this.ignite = Ignition.start(cfg);
-
+    public IgniteRepositoryFactory(ApplicationContext ctx) {
         this.ctx = ctx;
 
-        this.beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
+        beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
+
+        beanExpressionContext = new BeanExpressionContext(beanFactory, null);
+    }
 
-        this.beanExpressionContext = new BeanExpressionContext(beanFactory, null);
+    private Ignite igniteForRepoConfig(RepositoryConfig config) {
+        try {
+            String igniteInstanceName = evaluateExpression(config.igniteInstance());
+            return (Ignite)ctx.getBean(igniteInstanceName);
+        }
+        catch (BeansException ex) {
+            try {
+                String igniteConfigName = evaluateExpression(config.igniteCfg());
+                IgniteConfiguration cfg = (IgniteConfiguration)ctx.getBean(igniteConfigName);
+                try {
+                    // first try to attach to existing ignite instance
+                    return Ignition.ignite(cfg.getIgniteInstanceName());
+                }
+                catch (Exception ignored) {
+                    // nop
+                }
+                return Ignition.start(cfg);
+            }
+            catch (BeansException ex2) {
+                try {
+                    String igniteSpringCfgPath = evaluateExpression(config.igniteSpringCfgPath());
+                    String path = (String)ctx.getBean(igniteSpringCfgPath);
+                    return Ignition.start(path);
+                }
+                catch (BeansException ex3) {
+                    throw new IgniteException("Failed to initialize Ignite repository factory. Ignite instance or"
+                        + " IgniteConfiguration or a path to Ignite's spring XML "
+                        + "configuration must be defined in the"
+                        + " application configuration");
+                }
+            }
+        }
     }
 
     /**
-     * Initializes the factory with provided a configuration under {@code springCfgPath} that is used to start up
-     * an underlying {@link Ignite} instance.
+     * {@inheritDoc} @param <T>  the type parameter
      *
-     * @param springCfgPath A path to Ignite configuration.
+     * @param <ID>        the type parameter
+     * @param domainClass the domain class
+     * @return the entity information
      */
-    public IgniteRepositoryFactory(String springCfgPath, ApplicationContext ctx) {
-        this.ignite = Ignition.start(springCfgPath);
-
-        this.ctx = ctx;
-
-        this.beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
-
-        this.beanExpressionContext = new BeanExpressionContext(beanFactory, null);
-    }
-
-    /** {@inheritDoc} */
     @Override public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
         return new AbstractEntityInformation<T, ID>(domainClass) {
             @Override public ID getId(T entity) {
@@ -125,71 +154,123 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         };
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc} @param metadata the metadata
+     *
+     * @return the repository base class
+     */
     @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
         return IgniteRepositoryImpl.class;
     }
 
-    /** {@inheritDoc} */
-    @Override protected RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
+    /**
+     * {@inheritDoc} @param repoItf the repo itf
+     *
+     * @return the repository metadata
+     */
+    @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
         Assert.notNull(repoItf, "Repository interface must be set.");
         Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
 
         RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
 
-        Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map " +
-            "this repository to the underlying cache.");
+        Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map "
+            + "this repository to the underlying cache.");
 
-        Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig " +
-            "annotation to map this repository to the underlying cache.");
+        Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig "
+            + "annotation to map this repository to the underlying cache.");
 
         String cacheName = evaluateExpression(annotation.cacheName());
 
         repoToCache.put(repoItf, cacheName);
 
+        repoToIgnite.put(repoItf, igniteForRepoConfig(annotation));
+
         return super.getRepositoryMetadata(repoItf);
     }
 
     /**
-     *  evaluate the SpEL expression
+     * evaluate the SpEL expression
      *
      * @param spelExpression SpEL expression
      * @return the result of execution of the SpEL expression
      */
-    @NotNull private String evaluateExpression(String spelExpression) {
+    @NotNull
+    private String evaluateExpression(String spelExpression) {
         return (String)resolver.evaluate(spelExpression, beanExpressionContext);
     }
 
-    /** {@inheritDoc} */
+    /* control underline cache creation to avoid cache creation by mistake */
+    private IgniteCache getRepositoryCache(Class<?> repoIf) {
+        Ignite ignite = repoToIgnite.get(repoIf);
+
+        RepositoryConfig config = repoIf.getAnnotation(RepositoryConfig.class);
+
+        String cacheName = repoToCache.get(repoIf);
+
+        IgniteCache c = config.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
+
+        if (c == null) {
+            throw new IllegalStateException(
+                "Cache '" + cacheName + "' not found for repository interface " + repoIf.getName()
+                    + ". Please, add a cache configuration to ignite configuration"
+                    + " or pass autoCreateCache=true to org.apache.ignite.springdata20"
+                    + ".repository.config.RepositoryConfig annotation.");
+        }
+
+        return c;
+    }
+
+    /**
+     * {@inheritDoc} @param metadata the metadata
+     *
+     * @return the target repository
+     */
     @Override protected Object getTargetRepository(RepositoryInformation metadata) {
-        return getTargetRepositoryViaReflection(metadata,
-            ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+        Ignite ignite = repoToIgnite.get(metadata.getRepositoryInterface());
+        return getTargetRepositoryViaReflection(metadata, ignite,
+            getRepositoryCache(metadata.getRepositoryInterface()));
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc} @param key the key
+     *
+     * @param evaluationContextProvider the evaluation context provider
+     * @return the query lookup strategy
+     */
     @Override protected Optional<QueryLookupStrategy> getQueryLookupStrategy(final QueryLookupStrategy.Key key,
-        EvaluationContextProvider evaluationCtxProvider) {
+        EvaluationContextProvider evaluationContextProvider) {
         return Optional.of((mtd, metadata, factory, namedQueries) -> {
 
             final Query annotation = mtd.getAnnotation(Query.class);
+            final Ignite ignite = repoToIgnite.get(metadata.getRepositoryInterface());
 
-            if (annotation != null) {
-                String qryStr = annotation.value();
+            if (annotation != null && (StringUtils.hasText(annotation.value()) || annotation.textQuery() || annotation
+                .dynamicQuery())) {
 
-                if (key != QueryLookupStrategy.Key.CREATE && StringUtils.hasText(qryStr)) {
-                    return new IgniteRepositoryQuery(metadata,
-                            new IgniteQuery(qryStr, isFieldQuery(qryStr), IgniteQueryGenerator.getOptions(mtd)),
-                            mtd, factory, ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+                String qryStr = annotation.value();
+                boolean annotatedIgniteQuery = !annotation.dynamicQuery() && (StringUtils.hasText(qryStr) || annotation
+                    .textQuery());
+                IgniteQuery query = annotatedIgniteQuery ? new IgniteQuery(qryStr,
+                    !annotation.textQuery() && (isFieldQuery(qryStr) || annotation.forceFieldsQuery()),
+                    annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
+                if (key != QueryLookupStrategy.Key.CREATE) {
+                    return new IgniteRepositoryQuery(ignite, metadata, query, mtd, factory,
+                        getRepositoryCache(metadata.getRepositoryInterface()),
+                        annotatedIgniteQuery ? DynamicQueryConfig.fromQueryAnnotation(annotation) : null,
+                        evaluationContextProvider);
                 }
             }
 
             if (key == QueryLookupStrategy.Key.USE_DECLARED_QUERY) {
-                throw new IllegalStateException("To use QueryLookupStrategy.Key.USE_DECLARED_QUERY, pass " +
-                        "a query string via org.apache.ignite.springdata.repository.config.Query annotation.");
+                throw new IllegalStateException("To use QueryLookupStrategy.Key.USE_DECLARED_QUERY, pass "
+                    + "a query string via org.apache.ignite.springdata20.repository"
+                    + ".config.Query annotation.");
             }
 
-            return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
-                factory, ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+            return new IgniteRepositoryQuery(ignite, metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
+                factory, getRepositoryCache(metadata.getRepositoryInterface()),
+                DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
         });
     }
 
@@ -197,7 +278,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
      * @param qry Query string.
      * @return {@code true} if query is SqlFieldsQuery.
      */
-    private boolean isFieldQuery(String qry) {
+    public static boolean isFieldQuery(String qry) {
         String qryUpperCase = qry.toUpperCase();
 
         return isStatement(qryUpperCase) && !qryUpperCase.matches("^SELECT\\s+(?:\\w+\\.)?+\\*.*");
@@ -207,11 +288,19 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
      * Evaluates if the query starts with a clause.<br>
      * <code>SELECT, INSERT, UPDATE, MERGE, DELETE</code>
      *
-     * @param qryUpperCase  Query string in upper case.
+     * @param qryUpperCase Query string in upper case.
      * @return {@code true} if query is full SQL statement.
      */
-    private boolean isStatement(String qryUpperCase ) {
-        return qryUpperCase.matches("^\\s*SELECT\\b.*") || qryUpperCase.matches("^\\s*UPDATE\\b.*") || qryUpperCase.matches("^\\s*DELETE\\b.*") ||
-            qryUpperCase.matches("^\\s*MERGE\\b.*") || qryUpperCase.matches("^\\s*INSERT\\b.*");
+    private static boolean isStatement(String qryUpperCase) {
+        return qryUpperCase.matches("^\\s*SELECT\\b.*") ||
+            // update
+            qryUpperCase.matches("^\\s*UPDATE\\b.*") ||
+            // delete
+            qryUpperCase.matches("^\\s*DELETE\\b.*") ||
+            // merge
+            qryUpperCase.matches("^\\s*MERGE\\b.*") ||
+            // insert
+            qryUpperCase.matches("^\\s*INSERT\\b.*");
     }
+
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
index 3197330..fa94574 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
@@ -19,7 +19,6 @@ package org.apache.ignite.springdata20.repository.support;
 
 import java.io.Serializable;
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.springdata20.repository.IgniteRepository;
 import org.springframework.beans.BeansException;
@@ -31,61 +30,44 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
 
 /**
  * Apache Ignite repository factory bean.
- *
- * The repository requires to define one of the parameters below in your Spring application configuration in order
- * to get an access to Apache Ignite cluster:
+ * <p>
+ * The {@link org.apache.ignite.springdata20.repository.config.RepositoryConfig} requires to define one of the
+ * parameters below in your Spring application configuration in order to get an access to Apache Ignite cluster:
  * <ul>
- * <li>{@link Ignite} instance bean named "igniteInstance"</li>
- * <li>{@link IgniteConfiguration} bean named "igniteCfg"</li>
- * <li>A path to Ignite's Spring XML configuration named "igniteSpringCfgPath"</li>
+ * <li>{@link Ignite} instance bean named "igniteInstance" by default</li>
+ * <li>{@link IgniteConfiguration} bean named "igniteCfg" by default</li>
+ * <li>A path to Ignite's Spring XML configuration named "igniteSpringCfgPath" by default</li>
  * <ul/>
  *
  * @param <T> Repository type, {@link IgniteRepository}
- * @param <S> Domain object class.
- * @param <ID> Domain object key, super expects {@link Serializable}.
+ * @param <V> Domain object class.
+ * @param <K> Domain object key, super expects {@link Serializable}.
  */
-public class IgniteRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
-    extends RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
-    /** Application context. */
+public class IgniteRepositoryFactoryBean<T extends Repository<V, K>, V, K extends Serializable>
+    extends RepositoryFactoryBeanSupport<T, V, K> implements ApplicationContextAware {
+    /**
+     * Application context.
+     */
     private ApplicationContext ctx;
 
     /**
-     * @param repositoryInterface Repository interface.
+     * @param repoInterface Repository interface.
      */
-    protected IgniteRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
-        super(repositoryInterface);
+    protected IgniteRepositoryFactoryBean(Class<? extends T> repoInterface) {
+        super(repoInterface);
     }
 
-    /** {@inheritDoc} */
-    @Override public void setApplicationContext(ApplicationContext context) throws BeansException {
-        this.ctx = context;
+    /**
+     * {@inheritDoc}
+     */
+    @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+        this.ctx = ctx;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected RepositoryFactorySupport createRepositoryFactory() {
-        try {
-            Ignite ignite = (Ignite)ctx.getBean("igniteInstance");
-
-            return new IgniteRepositoryFactory(ignite, ctx );
-        }
-        catch (BeansException ex) {
-            try {
-                IgniteConfiguration cfg = (IgniteConfiguration)ctx.getBean("igniteCfg");
-
-                return new IgniteRepositoryFactory(cfg, ctx);
-            }
-            catch (BeansException ex2) {
-                try {
-                    String path = (String)ctx.getBean("igniteSpringCfgPath");
-
-                    return new IgniteRepositoryFactory(path, ctx );
-                }
-                catch (BeansException ex3) {
-                    throw new IgniteException("Failed to initialize Ignite repository factory. Ignite instance or" +
-                        " IgniteConfiguration or a path to Ignite's spring XML configuration must be defined in the" +
-                        " application configuration");
-                }
-            }
-        }
+        return new IgniteRepositoryFactory(ctx);
     }
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
index c9cfded..3c32f7b 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
@@ -17,6 +17,7 @@
 package org.apache.ignite.springdata20.repository.support;
 
 import java.io.Serializable;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
@@ -24,77 +25,168 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.TreeSet;
 import javax.cache.Cache;
+import javax.cache.expiry.ExpiryPolicy;
+import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.CachePeekMode;
 import org.apache.ignite.springdata20.repository.IgniteRepository;
 import org.springframework.context.annotation.Conditional;
-
-import static java.util.Collections.emptySet;
+import org.springframework.lang.Nullable;
 
 /**
- * General Apache Ignite repository implementation.
- * This bean should've never been loaded by context directly, only via {@link IgniteRepositoryFactory}
+ * General Apache Ignite repository implementation. This bean should've never been loaded by context directly, only via
+ * {@link IgniteRepositoryFactory}
+ *
+ * @param <V> the cache value type
+ * @param <K> the cache key type
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 @Conditional(ConditionFalse.class)
-public class IgniteRepositoryImpl<T, ID extends Serializable> implements IgniteRepository<T, ID> {
-    /** Ignite Cache bound to the repository */
-    private final IgniteCache<ID, T> cache;
+public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRepository<V, K> {
+    /**
+     * Ignite Cache bound to the repository
+     */
+    private final IgniteCache<K, V> cache;
+
+    /**
+     * Ignite instance bound to the repository
+     */
+    private final Ignite ignite;
 
     /**
      * Repository constructor.
      *
-     * @param cache Initialized cache instance.
+     * @param ignite the ignite
+     * @param cache  Initialized cache instance.
      */
-    public IgniteRepositoryImpl(IgniteCache<ID, T> cache) {
+    public IgniteRepositoryImpl(Ignite ignite, IgniteCache<K, V> cache) {
         this.cache = cache;
+        this.ignite = ignite;
     }
 
-    /** {@inheritDoc} */
-    @Override public <S extends T> S save(ID key, S entity) {
+    /**
+     * {@inheritDoc} @return the ignite cache
+     */
+    @Override public IgniteCache<K, V> cache() {
+        return cache;
+    }
+
+    /**
+     * {@inheritDoc} @return the ignite
+     */
+    @Override public Ignite ignite() {
+        return ignite;
+    }
+
+    /**
+     * {@inheritDoc} @param <S>  the type parameter
+     *
+     * @param key    the key
+     * @param entity the entity
+     * @return the s
+     */
+    @Override public <S extends V> S save(K key, S entity) {
         cache.put(key, entity);
 
         return entity;
     }
 
-    /** {@inheritDoc} */
-    @Override public <S extends T> Iterable<S> save(Map<ID, S> entities) {
+    /**
+     * {@inheritDoc} @param <S>  the type parameter
+     *
+     * @param entities the entities
+     * @return the iterable
+     */
+    @Override public <S extends V> Iterable<S> save(Map<K, S> entities) {
         cache.putAll(entities);
 
         return entities.values();
     }
 
-    /** {@inheritDoc} */
-    @Override public <S extends T> S save(S entity) {
+    /**
+     * {@inheritDoc} @param <S>  the type parameter
+     *
+     * @param key       the key
+     * @param entity    the entity
+     * @param expiryPlc the expiry policy
+     * @return the s
+     */
+    @Override public <S extends V> S save(K key, S entity, @Nullable ExpiryPolicy expiryPlc) {
+        if (expiryPlc != null)
+            cache.withExpiryPolicy(expiryPlc).put(key, entity);
+        else
+            cache.put(key, entity);
+        return entity;
+    }
+
+    /**
+     * {@inheritDoc} @param <S>  the type parameter
+     *
+     * @param entities  the entities
+     * @param expiryPlc the expiry policy
+     * @return the iterable
+     */
+    @Override public <S extends V> Iterable<S> save(Map<K, S> entities, @Nullable ExpiryPolicy expiryPlc) {
+        if (expiryPlc != null)
+            cache.withExpiryPolicy(expiryPlc).putAll(entities);
+        else
+            cache.putAll(entities);
+        return entities.values();
+    }
+
+    /**
+     * {@inheritDoc} @param <S>  the type parameter
+     *
+     * @param entity the entity
+     * @return the s
+     */
+    @Override public <S extends V> S save(S entity) {
         throw new UnsupportedOperationException("Use IgniteRepository.save(key,value) method instead.");
     }
 
-    /** {@inheritDoc} */
-    @Override public <S extends T> Iterable<S> saveAll(Iterable<S> entities) {
+    /**
+     * {@inheritDoc} @param <S>  the type parameter
+     *
+     * @param entities the entities
+     * @return the iterable
+     */
+    @Override public <S extends V> Iterable<S> saveAll(Iterable<S> entities) {
         throw new UnsupportedOperationException("Use IgniteRepository.save(Map<keys,value>) method instead.");
     }
 
-    /** {@inheritDoc} */
-    @Override public Optional<T> findById(ID id) {
+    /**
+     * {@inheritDoc} @param id the id
+     *
+     * @return the optional
+     */
+    @Override public Optional<V> findById(K id) {
         return Optional.ofNullable(cache.get(id));
     }
 
-    /** {@inheritDoc} */
-    @Override public boolean existsById(ID id) {
+    /**
+     * {@inheritDoc} @param id the id
+     *
+     * @return the boolean
+     */
+    @Override public boolean existsById(K id) {
         return cache.containsKey(id);
     }
 
-    /** {@inheritDoc} */
-    @Override public Iterable<T> findAll() {
-        final Iterator<Cache.Entry<ID, T>> iter = cache.iterator();
+    /**
+     * {@inheritDoc} @return the iterable
+     */
+    @Override public Iterable<V> findAll() {
+        final Iterator<Cache.Entry<K, V>> iter = cache.iterator();
 
-        return new Iterable<T>() {
-            @Override public Iterator<T> iterator() {
-                return new Iterator<T>() {
+        return new Iterable<V>() {
+            @Override public Iterator<V> iterator() {
+                return new Iterator<V>() {
                     @Override public boolean hasNext() {
                         return iter.hasNext();
                     }
 
-                    @Override public T next() {
+                    @Override public V next() {
                         return iter.next().getValue();
                     }
 
@@ -107,65 +199,80 @@ public class IgniteRepositoryImpl<T, ID extends Serializable> implements IgniteR
     }
 
     /**
-     * @param ids Collection of IDs.
-     * @return Collection transformed to set.
+     * {@inheritDoc} @param ids the ids
+     *
+     * @return the iterable
      */
-    private Set<ID> toSet(Iterable<ID> ids) {
+    @Override public Iterable<V> findAllById(Iterable<K> ids) {
         if (ids instanceof Set)
-            return (Set<ID>)ids;
-
-        Iterator<ID> itr = ids.iterator();
-
-        if (!itr.hasNext())
-            return emptySet();
+            return cache.getAll((Set<K>)ids).values();
 
-        ID key = itr.next();
+        if (ids instanceof Collection)
+            return cache.getAll(new HashSet<>((Collection<K>)ids)).values();
 
-        Set<ID> keys = key instanceof Comparable ? new TreeSet<>() : new HashSet<>();
+        TreeSet<K> keys = new TreeSet<>();
 
-        keys.add(key);
+        for (K id : ids)
+            keys.add(id);
 
-        while (itr.hasNext()) {
-            key = itr.next();
-
-            keys.add(key);
-        }
-
-        return keys;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Iterable<T> findAllById(Iterable<ID> ids) {
-        return cache.getAll(toSet(ids)).values();
+        return cache.getAll(keys).values();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc} @return the long
+     */
     @Override public long count() {
         return cache.size(CachePeekMode.PRIMARY);
     }
 
-    /** {@inheritDoc} */
-    @Override public void deleteById(ID id) {
+    /**
+     * {@inheritDoc} @param id the id
+     */
+    @Override public void deleteById(K id) {
         cache.remove(id);
     }
 
-    /** {@inheritDoc} */
-    @Override public void delete(T entity) {
+    /**
+     * {@inheritDoc} @param entity the entity
+     */
+    @Override public void delete(V entity) {
         throw new UnsupportedOperationException("Use IgniteRepository.deleteById(key) method instead.");
     }
 
-    /** {@inheritDoc} */
-    @Override public void deleteAll(Iterable<? extends T> entities) {
+    /**
+     * {@inheritDoc} @param entities the entities
+     */
+    @Override public void deleteAll(Iterable<? extends V> entities) {
         throw new UnsupportedOperationException("Use IgniteRepository.deleteAllById(keys) method instead.");
     }
 
-    /** {@inheritDoc} */
-    @Override public void deleteAllById(Iterable<ID> ids) {
-        cache.removeAll(toSet(ids));
+    /**
+     * {@inheritDoc} @param ids the ids
+     */
+    @Override public void deleteAllById(Iterable<K> ids) {
+        if (ids instanceof Set) {
+            cache.removeAll((Set<K>)ids);
+            return;
+        }
+
+        if (ids instanceof Collection) {
+            cache.removeAll(new HashSet<>((Collection<K>)ids));
+            return;
+        }
+
+        TreeSet<K> keys = new TreeSet<>();
+
+        for (K id : ids)
+            keys.add(id);
+
+        cache.removeAll(keys);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override public void deleteAll() {
         cache.clear();
     }
+
 }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
index 11144e4..47417ee 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
@@ -31,20 +31,30 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
  * Test with using repository which is configured by Spring EL
  */
 public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTest {
-    /** Number of entries to store */
+    /**
+     * Number of entries to store
+     */
     private static final int CACHE_SIZE = 1000;
 
-    /** Repository. */
+    /**
+     * Repository.
+     */
     private static PersonExpressionRepository repo;
 
-    /** Context. */
+    /**
+     * Context.
+     */
     private static AnnotationConfigApplicationContext ctx;
 
-    /** */
+    /**
+     *
+     */
     @Rule
     public final ExpectedException expected = ExpectedException.none();
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
@@ -55,7 +65,9 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         repo = ctx.getBean(PersonExpressionRepository.class);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
 
@@ -64,7 +76,9 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         assertEquals(CACHE_SIZE, repo.count());
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected void afterTest() throws Exception {
         repo.deleteAll();
 
@@ -73,21 +87,25 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         super.afterTest();
     }
 
-    /** */
+    /**
+     *
+     */
     private void fillInRepository() {
         for (int i = 0; i < CACHE_SIZE - 5; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
                 "lastName" + Integer.toHexString((i + 16) % 256)));
         }
 
-        repo.save((int) repo.count(), new Person("uniquePerson", "uniqueLastName"));
-        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int)repo.count(), new Person("uniquePerson", "uniqueLastName"));
+        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected void afterTestsStopped() {
         ctx.close();
     }
@@ -117,7 +135,20 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
      */
     @Test
     public void testCacheCount() {
-        Ignite ignite = ctx.getBean(Ignite.class);
+        Ignite ignite = ctx.getBean("igniteInstance", Ignite.class);
+
+        Collection<String> cacheNames = ignite.cacheNames();
+
+        assertFalse("The SpEL \"#{cacheNames.personCacheName}\" isn't processed!",
+            cacheNames.contains("#{cacheNames.personCacheName}"));
+
+        assertTrue("Cache \"PersonCache\" isn't found!",
+            cacheNames.contains("PersonCache"));
+    }
+
+    @Test
+    public void testCacheCountTWO() {
+        Ignite ignite = ctx.getBean("igniteInstanceTWO", Ignite.class);
 
         Collection<String> cacheNames = ignite.cacheNames();
 
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
index b4dcf23..5b52092 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
@@ -23,55 +23,39 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Optional;
 import java.util.TreeSet;
-import javax.cache.CacheException;
-import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.internal.processors.query.RunningQueryManager;
-import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 import org.apache.ignite.springdata.misc.ApplicationConfiguration;
+import org.apache.ignite.springdata.misc.FullNameProjection;
 import org.apache.ignite.springdata.misc.Person;
-import org.apache.ignite.springdata.misc.PersonKey;
+import org.apache.ignite.springdata.misc.PersonProjection;
 import org.apache.ignite.springdata.misc.PersonRepository;
-import org.apache.ignite.springdata.misc.PersonRepositoryWithCompoundKey;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
 /**
- * CRUD tests.
+ *
  */
 public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
-    /** Number of entries to store */
-    private static final int CACHE_SIZE = 1000;
-
     /** Repository. */
     private static PersonRepository repo;
 
-    /** Repository. */
-    private static PersonRepositoryWithCompoundKey repoWithCompoundKey;
-
     /** Context. */
     private static AnnotationConfigApplicationContext ctx;
 
-    /** */
-    @Rule
-    public final ExpectedException expected = ExpectedException.none();
-
-    /** */
-    private static IgniteEx ignite;
+    /** Number of entries to store */
+    private static int CACHE_SIZE = 1000;
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
         ctx = new AnnotationConfigApplicationContext();
+
         ctx.register(ApplicationConfiguration.class);
+
         ctx.refresh();
 
         repo = ctx.getBean(PersonRepository.class);
-        repoWithCompoundKey = ctx.getBean(PersonRepositoryWithCompoundKey.class);
-        ignite = ctx.getBean(IgniteEx.class);
     }
 
     /** {@inheritDoc} */
@@ -92,7 +76,9 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         super.afterTest();
     }
 
-    /** */
+    /**
+     *
+     */
     private void fillInRepository() {
         for (int i = 0; i < CACHE_SIZE - 5; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
@@ -107,11 +93,13 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() {
-        ctx.close();
+    @Override protected void afterTestsStopped() throws Exception {
+        ctx.destroy();
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testPutGet() {
         Person person = new Person("some_name", "some_surname");
@@ -124,12 +112,19 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
 
         assertEquals(person, repo.findById(id).get());
 
-        expected.expect(UnsupportedOperationException.class);
-        expected.expectMessage("Use IgniteRepository.save(key,value) method instead.");
-        repo.save(person);
+        try {
+            repo.save(person);
+
+            fail("Managed to save a Person without ID");
+        }
+        catch (UnsupportedOperationException e) {
+            //excepted
+        }
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testPutAllGetAll() {
         LinkedHashMap<Integer, Person> map = new LinkedHashMap<>();
@@ -146,9 +141,14 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         while (persons.hasNext())
             assertEquals(origPersons.next(), persons.next());
 
-        expected.expect(UnsupportedOperationException.class);
-        expected.expectMessage("Use IgniteRepository.save(Map<keys,value>) method instead.");
-        repo.saveAll(map.values());
+        try {
+            repo.saveAll(map.values());
+
+            fail("Managed to save a list of Persons with ids");
+        }
+        catch (UnsupportedOperationException e) {
+            //expected
+        }
 
         persons = repo.findAllById(map.keySet()).iterator();
 
@@ -162,7 +162,9 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(map.size(), counter);
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testGetAll() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -179,7 +181,9 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(repo.count(), counter);
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testDelete() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -189,12 +193,19 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(CACHE_SIZE - 1, repo.count());
         assertEquals(Optional.empty(),repo.findById(0));
 
-        expected.expect(UnsupportedOperationException.class);
-        expected.expectMessage("Use IgniteRepository.deleteById(key) method instead.");
-        repo.delete(new Person("", ""));
+        try {
+            repo.delete(new Person("", ""));
+
+            fail("Managed to delete a Person without id");
+        }
+        catch (UnsupportedOperationException e) {
+            //expected
+        }
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testDeleteSet() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -208,17 +219,24 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
 
         assertEquals(CACHE_SIZE / 2, repo.count());
 
-        ArrayList<Person> persons = new ArrayList<>();
+        try {
+            ArrayList<Person> persons = new ArrayList<>();
 
-        for (int i = 0; i < 3; i++)
-            persons.add(new Person(String.valueOf(i), String.valueOf(i)));
+            for (int i = 0; i < 3; i++)
+                persons.add(new Person(String.valueOf(i), String.valueOf(i)));
 
-        expected.expect(UnsupportedOperationException.class);
-        expected.expectMessage("Use IgniteRepository.deleteAllById(keys) method instead.");
-        repo.deleteAll(persons);
+            repo.deleteAll(persons);
+
+            fail("Managed to delete Persons without ids");
+        }
+        catch (UnsupportedOperationException e) {
+            //expected
+        }
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testDeleteAll() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -229,7 +247,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete existing record.
+     * Delete existing record
      */
     @Test
     public void testDeleteByFirstName() {
@@ -241,7 +259,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete NON existing record.
+     * Delete NON existing record
      */
     @Test
     public void testDeleteExpression() {
@@ -251,54 +269,58 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete Multiple records due to where.
+     * Delete Multiple records due to where
      */
     @Test
     public void testDeleteExpressionMultiple() {
-        long cnt = repo.countByFirstName("nonUniquePerson");
-        long cntDeleted = repo.deleteByFirstName("nonUniquePerson");
+        long count = repo.countByFirstName("nonUniquePerson");
+        long cnt = repo.deleteByFirstName("nonUniquePerson");
 
-        assertEquals(cntDeleted, cnt);
+        assertEquals(cnt, count);
     }
 
     /**
-     * Remove should do the same than Delete.
+     * Remove should do the same than Delete
      */
     @Test
     public void testRemoveExpression() {
         repo.removeByFirstName("person3f");
 
-        long cnt = repo.count();
-        assertEquals(CACHE_SIZE - 1, cnt);
+        long count = repo.count();
+        assertEquals(CACHE_SIZE - 1, count);
     }
 
     /**
-     * Delete unique record using lower case key word.
+     * Delete unique record using lower case key word
      */
     @Test
     public void testDeleteQuery() {
         repo.deleteBySecondNameLowerCase("uniqueLastName");
 
-        long cntAfter = repo.count();
-        assertEquals(CACHE_SIZE - 1, cntAfter);
+        long countAfter = repo.count();
+        assertEquals(CACHE_SIZE - 1, countAfter);
     }
 
     /**
-     * Try to delete with a wrong @Query.
+     * Try to delete with a wrong @Query
      */
     @Test
     public void testWrongDeleteQuery() {
-        long cntBefore = repo.countByFirstNameLike("person3f");
+        long countBefore = repo.countByFirstNameLike("person3f");
 
-        expected.expect(CacheException.class);
-        repo.deleteWrongByFirstNameQuery("person3f");
+        try {
+            repo.deleteWrongByFirstNameQuery("person3f");
+        }
+        catch (Exception e) {
+            //expected
+        }
 
-        long cntAfter = repo.countByFirstNameLike("person3f");
-        assertEquals(cntBefore, cntAfter);
+        long countAfter = repo.countByFirstNameLike("person3f");
+        assertEquals(countBefore, countAfter);
     }
 
     /**
-     * Update with a @Query a record.
+     * Update with a @Query a record
      */
     @Test
     public void testUpdateQueryMixedCase() {
@@ -312,81 +334,120 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Update with a wrong @Query.
+     * Update with a @Query a record
      */
     @Test
-    public void testWrongUpdateQuery() {
-        expected.expect(CacheException.class);
-        int rowsUpdated = repo.setWrongFixedSecondName("updatedUniqueSecondName", "uniquePerson");
+    public void testUpdateQueryMixedCaseProjection() {
+        final String newSecondName = "updatedUniqueSecondName1";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        assertEquals(0, rowsUpdated);
+        assertEquals(1, cnt);
 
-        List<Person> person = repo.findByFirstName("uniquePerson");
-        assertEquals(person.get(0).getSecondName(), "uniqueLastName");
+        List<PersonProjection> person = repo.queryByFirstNameWithProjection("uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName1");
     }
 
-    /** */
     @Test
-    public void shouldDeleteAllById() {
-        List<PersonKey> ids = prepareDataWithNonComparableKeys();
+    public void testUpdateQueryMixedCaseProjectionNamedParameter() {
+        final String newSecondName = "updatedUniqueSecondName2";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        repoWithCompoundKey.deleteAllById(ids);
+        assertEquals(1, cnt);
 
-        assertEquals(0, repoWithCompoundKey.count());
+        List<PersonProjection> person = repo.queryByFirstNameWithProjectionNamedParameter("uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
-    /** */
     @Test
-    public void shouldFindAllById() {
-        List<PersonKey> ids = prepareDataWithNonComparableKeys();
+    public void testUpdateQueryMixedCaseDynamicProjectionNamedParameter() {
+        final String newSecondName = "updatedUniqueSecondName2";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        Iterable<Person> res = repoWithCompoundKey.findAllById(ids);
+        assertEquals(1, cnt);
 
-        assertEquals(2, res.spliterator().estimateSize());
+        List<PersonProjection> person = repo.queryByFirstNameWithProjectionNamedParameter(PersonProjection.class, "uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
+
+        List<FullNameProjection> personFullName = repo.queryByFirstNameWithProjectionNamedParameter(FullNameProjection.class, "uniquePerson");
+        assertEquals(personFullName.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
-    /** */
-    private List<PersonKey> prepareDataWithNonComparableKeys() {
-        List<PersonKey> ids = new ArrayList<>();
+    @Test
+    public void testUpdateQueryOneMixedCaseDynamicProjectionNamedParameter() {
+        final String newSecondName = "updatedUniqueSecondName2";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        PersonKey key = new PersonKey(1, 1);
-        ids.add(key);
+        assertEquals(1, cnt);
 
-        repoWithCompoundKey.save(key, new Person("test1", "test1"));
+        PersonProjection person = repo.queryOneByFirstNameWithProjectionNamedParameter(PersonProjection.class, "uniquePerson");
+        assertEquals(person.getFullName(), "uniquePerson updatedUniqueSecondName2");
 
-        key = new PersonKey(2, 2);
-        ids.add(key);
+        FullNameProjection personFullName = repo.queryOneByFirstNameWithProjectionNamedParameter(FullNameProjection.class, "uniquePerson");
+        assertEquals(personFullName.getFullName(), "uniquePerson updatedUniqueSecondName2");
+    }
 
-        repoWithCompoundKey.save(key, new Person("test2", "test2"));
+    @Test
+    public void testUpdateQueryMixedCaseProjectionIndexedParameter() {
+        final String newSecondName = "updatedUniqueSecondName3";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        assertEquals(2, repoWithCompoundKey.count());
+        assertEquals(1, cnt);
 
-        return ids;
+        List<PersonProjection> person = repo.queryByFirstNameWithProjectionNamedIndexedParameter("notUsed","uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName3");
     }
 
-    /** */
     @Test
-    public void shouldNotLeakCursorsInRunningQueryManager() {
-        RunningQueryManager runningQryMgr = ((IgniteH2Indexing)ignite.context().query().getIndexing()).runningQueryManager();
+    public void testUpdateQueryMixedCaseProjectionIndexedParameterLuceneTextQuery() {
+        final String newSecondName = "updatedUniqueSecondName4";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        assertEquals(0, runningQryMgr.longRunningQueries(0).size());
+        assertEquals(1, cnt);
 
-        List<Person> res = repo.simpleQuery("person0");
+        List<PersonProjection> person = repo.textQueryByFirstNameWithProjectionNamedParameter("uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName4");
+    }
 
-        assertEquals(1, res.size());
+    @Test
+    public void testUpdateQueryMixedCaseProjectionNamedParameterAndTemplateDomainEntityVariable() {
+        final String newSecondName = "updatedUniqueSecondName5";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        assertEquals(0, runningQryMgr.longRunningQueries(0).size());
+        assertEquals(1, cnt);
 
-        Person person = repo.findTopBySecondNameStartingWith("lastName");
+        List<PersonProjection> person = repo.queryByFirstNameWithProjectionNamedParameterAndTemplateDomainEntityVariable("uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName5");
+    }
 
-        assertNotNull(person);
+    @Test
+    public void testUpdateQueryMixedCaseProjectionNamedParameterWithSpELExtension() {
+        final String newSecondName = "updatedUniqueSecondName6";
+        int cnt = repo.setFixedSecondNameMixedCase(newSecondName, "uniquePerson");
 
-        assertEquals(0, runningQryMgr.longRunningQueries(0).size());
+        assertEquals(1, cnt);
 
-        long cnt = repo.countByFirstName("person0");
+        List<PersonProjection> person = repo.queryByFirstNameWithProjectionNamedParameterWithSpELExtension("uniquePerson");
+        assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName6");
+        assertEquals(person.get(0).getFirstName(), person.get(0).getFirstNameTransformed());
+    }
 
-        assertEquals(1, cnt);
+    /**
+     * Update with a wrong @Query
+     */
+    @Test
+    public void testWrongUpdateQuery() {
+        final String newSecondName = "updatedUniqueSecondName";
+        int rowsUpdated = 0;
+        try {
+            rowsUpdated = repo.setWrongFixedSecondName(newSecondName, "uniquePerson");
+        }
+        catch (Exception ignored) {
+            //expected
+        }
 
-        assertEquals(0, runningQryMgr.longRunningQueries(0).size());
+        assertEquals(0, rowsUpdated);
+
+        List<Person> person = repo.findByFirstName("uniquePerson");
+        assertEquals(person.get(0).getSecondName(), "uniqueLastName");
     }
 }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
index e1ed7f8..03b15a6 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
@@ -23,7 +23,9 @@ import java.util.List;
 import javax.cache.Cache;
 import org.apache.ignite.springdata.misc.ApplicationConfiguration;
 import org.apache.ignite.springdata.misc.Person;
+import org.apache.ignite.springdata.misc.PersonProjection;
 import org.apache.ignite.springdata.misc.PersonRepository;
+import org.apache.ignite.springdata.misc.PersonRepositoryOtherIgniteInstance;
 import org.apache.ignite.springdata.misc.PersonSecondRepository;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
@@ -36,45 +38,66 @@ import org.springframework.data.domain.Sort;
  *
  */
 public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
-    /** Number of entries to store */
-    private static final int CACHE_SIZE = 1000;
-
-    /** Repository. */
+    /**
+     * Repository.
+     */
     private static PersonRepository repo;
 
-    /** Repository 2. */
+    /**
+     * Repository 2.
+     */
     private static PersonSecondRepository repo2;
 
-    /** Context. */
+    /**
+     * Repository Ignite Instance cluster TWO.
+     */
+    private static PersonRepositoryOtherIgniteInstance repoTWO;
+
+    /**
+     * Context.
+     */
     private static AnnotationConfigApplicationContext ctx;
 
     /**
+     * Number of entries to store
+     */
+    private static int CACHE_SIZE = 1000;
+
+    /**
      * Performs context initialization before tests.
      */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
         ctx = new AnnotationConfigApplicationContext();
+
         ctx.register(ApplicationConfiguration.class);
+
         ctx.refresh();
 
         repo = ctx.getBean(PersonRepository.class);
         repo2 = ctx.getBean(PersonSecondRepository.class);
+        // repository on another ignite instance (and another cluster)
+        repoTWO = ctx.getBean(PersonRepositoryOtherIgniteInstance.class);
 
         for (int i = 0; i < CACHE_SIZE; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
-                    "lastName" + Integer.toHexString((i + 16) % 256)));
+                "lastName" + Integer.toHexString((i + 16) % 256)));
+            repoTWO.save(i, new Person("TWOperson" + Integer.toHexString(i),
+                "lastName" + Integer.toHexString((i + 16) % 256)));
         }
     }
 
     /**
      * Performs context destroy after tests.
      */
-    @Override protected void afterTestsStopped() {
-        ctx.close();
+    @Override protected void afterTestsStopped() throws Exception {
+        ctx.destroy();
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testExplicitQuery() {
         List<Person> persons = repo.simpleQuery("person4a");
@@ -85,7 +108,19 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("person4a", person.getFirstName());
     }
 
-    /** */
+    @Test
+    public void testExplicitQueryTWO() {
+        List<Person> persons = repoTWO.simpleQuery("TWOperson4a");
+
+        assertFalse(persons.isEmpty());
+
+        for (Person person : persons)
+            assertEquals("TWOperson4a", person.getFirstName());
+    }
+
+    /**
+     *
+     */
     @Test
     public void testEqualsPart() {
         List<Person> persons = repo.findByFirstName("person4e");
@@ -96,7 +131,19 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("person4e", person.getFirstName());
     }
 
-    /** */
+    @Test
+    public void testEqualsPartTWO() {
+        List<Person> persons = repoTWO.findByFirstName("TWOperson4e");
+
+        assertFalse(persons.isEmpty());
+
+        for (Person person : persons)
+            assertEquals("TWOperson4e", person.getFirstName());
+    }
+
+    /**
+     *
+     */
     @Test
     public void testContainingPart() {
         List<Person> persons = repo.findByFirstNameContaining("person4");
@@ -107,7 +154,19 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(person.getFirstName().startsWith("person4"));
     }
 
-    /** */
+    @Test
+    public void testContainingPartTWO() {
+        List<Person> persons = repoTWO.findByFirstNameContaining("TWOperson4");
+
+        assertFalse(persons.isEmpty());
+
+        for (Person person : persons)
+            assertTrue(person.getFirstName().startsWith("TWOperson4"));
+    }
+
+    /**
+     *
+     */
     @Test
     public void testTopPart() {
         Iterable<Person> top = repo.findTopByFirstNameContaining("person4");
@@ -121,7 +180,22 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFirstName().startsWith("person4"));
     }
 
-    /** */
+    @Test
+    public void testTopPartTWO() {
+        Iterable<Person> top = repoTWO.findTopByFirstNameContaining("TWOperson4");
+
+        Iterator<Person> iter = top.iterator();
+
+        Person person = iter.next();
+
+        assertFalse(iter.hasNext());
+
+        assertTrue(person.getFirstName().startsWith("TWOperson4"));
+    }
+
+    /**
+     *
+     */
     @Test
     public void testLikeAndLimit() {
         Iterable<Person> like = repo.findFirst10ByFirstNameLike("person");
@@ -137,7 +211,24 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, cnt);
     }
 
-    /** */
+    @Test
+    public void testLikeAndLimitTWO() {
+        Iterable<Person> like = repoTWO.findFirst10ByFirstNameLike("TWOperson");
+
+        int cnt = 0;
+
+        for (Person next : like) {
+            assertTrue(next.getFirstName().contains("TWOperson"));
+
+            cnt++;
+        }
+
+        assertEquals(10, cnt);
+    }
+
+    /**
+     *
+     */
     @Test
     public void testCount() {
         int cnt = repo.countByFirstNameLike("person");
@@ -145,7 +236,16 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(1000, cnt);
     }
 
-    /** */
+    @Test
+    public void testCountTWO() {
+        int cnt = repoTWO.countByFirstNameLike("TWOperson");
+
+        assertEquals(1000, cnt);
+    }
+
+    /**
+     *
+     */
     @Test
     public void testCount2() {
         int cnt = repo.countByFirstNameLike("person4");
@@ -153,17 +253,26 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cnt < 1000);
     }
 
-    /** */
+    @Test
+    public void testCount2TWO() {
+        int cnt = repoTWO.countByFirstNameLike("TWOperson4");
+
+        assertTrue(cnt < 1000);
+    }
+
+    /**
+     *
+     */
     @Test
     public void testPageable() {
-        PageRequest pageable = PageRequest.of(1, 5, Sort.Direction.DESC, "firstName");
+        PageRequest pageable = new PageRequest(1, 5, Sort.Direction.DESC, "firstName");
+
+        HashSet<String> firstNames = new HashSet<>();
 
         List<Person> pageable1 = repo.findByFirstNameRegex("^[a-z]+$", pageable);
 
         assertEquals(5, pageable1.size());
 
-        HashSet<String> firstNames = new HashSet<>();
-
         for (Person person : pageable1) {
             firstNames.add(person.getFirstName());
 
@@ -183,7 +292,9 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, firstNames.size());
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testAndAndOr() {
         int cntAnd = repo.countByFirstNameLikeAndSecondNameLike("person1", "lastName1");
@@ -193,10 +304,12 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cntAnd <= cntOr);
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testQueryWithSort() {
-        List<Person> persons = repo.queryWithSort("^[a-z]+$", Sort.by(Sort.Direction.DESC, "secondName"));
+        List<Person> persons = repo.queryWithSort("^[a-z]+$", new Sort(Sort.Direction.DESC, "secondName"));
 
         Person previous = persons.get(0);
 
@@ -209,10 +322,12 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testQueryWithPaging() {
-        List<Person> persons = repo.queryWithPageable("^[a-z]+$", PageRequest.of(1, 7, Sort.Direction.DESC, "secondName"));
+        List<Person> persons = repo.queryWithPageable("^[a-z]+$", new PageRequest(1, 7, Sort.Direction.DESC, "secondName"));
 
         assertEquals(7, persons.size());
 
@@ -227,15 +342,19 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testQueryFields() {
-        List<String> persons = repo.selectField("^[a-z]+$", PageRequest.of(1, 7, Sort.Direction.DESC, "secondName"));
+        List<String> persons = repo.selectField("^[a-z]+$", new PageRequest(1, 7, Sort.Direction.DESC, "secondName"));
 
         assertEquals(7, persons.size());
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testFindCacheEntries() {
         List<Cache.Entry<Integer, Person>> cacheEntries = repo.findBySecondNameLike("stName1");
@@ -246,7 +365,9 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(entry.getValue().getSecondName().contains("stName1"));
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testFindOneCacheEntry() {
         Cache.Entry<Integer, Person> cacheEntry = repo.findTopBySecondNameLike("tName18");
@@ -256,20 +377,24 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cacheEntry.getValue().getSecondName().contains("tName18"));
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testFindOneValue() {
-        Person person = repo.findTopBySecondNameStartingWith("lastName18");
+        PersonProjection person = repo.findTopBySecondNameStartingWith("lastName18");
 
         assertNotNull(person);
 
-        assertTrue(person.getSecondName().startsWith("lastName18"));
+        assertTrue(person.getFullName().split("\\s")[1].startsWith("lastName18"));
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testSelectSeveralFields() {
-        List<List> lists = repo.selectSeveralField("^[a-z]+$", PageRequest.of(2, 6));
+        List<List> lists = repo.selectSeveralField("^[a-z]+$", new PageRequest(2, 6));
 
         assertEquals(6, lists.size());
 
@@ -280,7 +405,9 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testCountQuery() {
         int cnt = repo.countQuery(".*");
@@ -288,10 +415,12 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(256, cnt);
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testSliceOfCacheEntries() {
-        Slice<Cache.Entry<Integer, Person>> slice = repo2.findBySecondNameIsNot("lastName18", PageRequest.of(3, 4));
+        Slice<Cache.Entry<Integer, Person>> slice = repo2.findBySecondNameIsNot("lastName18", new PageRequest(3, 4));
 
         assertEquals(4, slice.getSize());
 
@@ -299,10 +428,12 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertFalse("lastName18".equals(entry.getValue().getSecondName()));
     }
 
-    /** */
+    /**
+     *
+     */
     @Test
     public void testSliceOfLists() {
-        Slice<List> lists = repo2.querySliceOfList("^[a-z]+$", PageRequest.of(0, 3));
+        Slice<List> lists = repo2.querySliceOfList("^[a-z]+$", new PageRequest(0, 3));
 
         assertEquals(3, lists.getSize());
 
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
index 950bd55..5ee327f 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
@@ -23,9 +23,11 @@ import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata.misc.SampleEvaluationContextExtension.SamplePassParamExtension;
 import org.apache.ignite.springdata20.repository.config.EnableIgniteRepositories;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.data.repository.query.spi.EvaluationContextExtension;
 
 /**
  *
@@ -33,6 +35,11 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 @EnableIgniteRepositories
 public class ApplicationConfiguration {
+
+    public static final String IGNITE_INSTANCE_ONE = "IGNITE_INSTANCE_ONE";
+
+    public static final String IGNITE_INSTANCE_TWO = "IGNITE_INSTANCE_TWO";
+
     /**
      * The bean with cache names
      */
@@ -45,18 +52,60 @@ public class ApplicationConfiguration {
         return bean;
     }
 
+    @Bean
+    public EvaluationContextExtension sampleSpELExtension() {
+        return new SampleEvaluationContextExtension();
+    }
+
+    @Bean(value = "sampleExtensionBean")
+    public SamplePassParamExtension sampleExtensionBean() {
+        return new SamplePassParamExtension();
+    }
+
     /**
-     * Ignite instance bean.
+     * Ignite instance bean - no instance name provided on RepositoryConfig
      */
     @Bean
     public Ignite igniteInstance() {
-        IgniteConfiguration cfg = new IgniteConfiguration()
-            .setCacheConfiguration(
-                new CacheConfiguration<Integer, Person>("PersonCache")
-                    .setIndexedTypes(Integer.class, Person.class),
-                new CacheConfiguration<PersonKey, Person>("PersonWithKeyCache")
-            )
-            .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(new TcpDiscoveryVmIpFinder(true)));
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setIgniteInstanceName(IGNITE_INSTANCE_ONE);
+
+        CacheConfiguration ccfg = new CacheConfiguration("PersonCache");
+
+        ccfg.setIndexedTypes(Integer.class, Person.class);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        TcpDiscoverySpi spi = new TcpDiscoverySpi();
+
+        spi.setIpFinder(new TcpDiscoveryVmIpFinder(true));
+
+        cfg.setDiscoverySpi(spi);
+
+        return Ignition.start(cfg);
+    }
+
+    /**
+     * Ignite instance bean with not default name
+     */
+    @Bean
+    public Ignite igniteInstanceTWO() {
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setIgniteInstanceName(IGNITE_INSTANCE_TWO);
+
+        CacheConfiguration ccfg = new CacheConfiguration("PersonCache");
+
+        ccfg.setIndexedTypes(Integer.class, Person.class);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        TcpDiscoverySpi spi = new TcpDiscoverySpi();
+
+        spi.setIpFinder(new TcpDiscoveryVmIpFinder(true));
+
+        cfg.setDiscoverySpi(spi);
 
         return Ignition.start(cfg);
     }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
similarity index 70%
copy from modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
copy to modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
index 156bbb3..9aca003 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
@@ -14,15 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.springdata.misc;
 
-import org.apache.ignite.springdata20.repository.IgniteRepository;
-import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
+import org.springframework.beans.factory.annotation.Value;
 
 /**
- * Test repository.
+ * Advanced SpEl Expressions into projection
+ *
+ * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
-@RepositoryConfig(cacheName = "PersonWithKeyCache")
-public interface PersonRepositoryWithCompoundKey extends IgniteRepository<Person, PersonKey> {
+public interface FullNameProjection {
+
+    /**
+     * Sample of using SpEL expression
+     * @return
+     */
+    @Value("#{target.firstName + ' ' + target.secondName}")
+    String getFullName();
 }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/Person.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/Person.java
index 154937f..531c67f 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/Person.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/Person.java
@@ -19,6 +19,7 @@ package org.apache.ignite.springdata.misc;
 
 import java.util.Objects;
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.cache.query.annotations.QueryTextField;
 
 /**
  * DTO class.
@@ -26,6 +27,7 @@ import org.apache.ignite.cache.query.annotations.QuerySqlField;
 public class Person {
     /** First name. */
     @QuerySqlField(index = true)
+    @QueryTextField
     private String firstName;
 
     /** Second name. */
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
similarity index 58%
copy from modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
copy to modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
index 156bbb3..c4cab06 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
@@ -14,15 +14,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.springdata.misc;
 
-import org.apache.ignite.springdata20.repository.IgniteRepository;
-import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
+import org.springframework.beans.factory.annotation.Value;
 
 /**
- * Test repository.
+ * Advanced SpEl Expressions into projection
+ *
+ * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
-@RepositoryConfig(cacheName = "PersonWithKeyCache")
-public interface PersonRepositoryWithCompoundKey extends IgniteRepository<Person, PersonKey> {
+public interface PersonProjection {
+
+    String getFirstName();
+
+    /**
+     * Sample of using registered spring bean into SpEL expression
+     * @return
+     */
+    @Value("#{@sampleExtensionBean.transformParam(target.firstName)}")
+    String getFirstNameTransformed();
+
+    /**
+     * Sample of using SpEL expression
+     * @return
+     */
+    @Value("#{target.firstName + ' ' + target.secondName}")
+    String getFullName();
 }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
index 0b9d4df..7cb437d 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
@@ -14,20 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.springdata.misc;
 
 import java.util.Collection;
 import java.util.List;
 import javax.cache.Cache;
-import org.apache.ignite.springdata20.repository.IgniteRepository;
 import org.apache.ignite.springdata20.repository.config.Query;
 import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
+import org.apache.ignite.springdata20.repository.IgniteRepository;
+import org.springframework.data.repository.query.Param;
 
 /**
- * Test repository.
+ *
  */
 @RepositoryConfig(cacheName = "PersonCache")
 public interface PersonRepository extends IgniteRepository<Person, Integer> {
@@ -35,6 +35,36 @@ public interface PersonRepository extends IgniteRepository<Person, Integer> {
     public List<Person> findByFirstName(String val);
 
     /** */
+    @Query("firstName = ?")
+    public List<PersonProjection> queryByFirstNameWithProjection(String val);
+
+    /** */
+    @Query("firstName = :firstname")
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedParameter(@Param("firstname") String val);
+
+    /** */
+    @Query("firstName = :firstname")
+    public <P> List<P> queryByFirstNameWithProjectionNamedParameter(Class<P> dynamicProjection, @Param("firstname") String val);
+
+    /** */
+    @Query("firstName = :firstname")
+    public <P> P queryOneByFirstNameWithProjectionNamedParameter(Class<P> dynamicProjection, @Param("firstname") String val);
+
+    /** */
+    @Query("firstName = ?#{[1]}")
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedIndexedParameter(@Param("notUsed") String notUsed, @Param("firstname") String val);
+
+    /** */
+    @Query(textQuery = true, value = "#{#firstname}", limit = 2)
+    public List<PersonProjection> textQueryByFirstNameWithProjectionNamedParameter(@Param("firstname") String val);
+
+    @Query(value = "select * from (sElecT * from #{#entityName} where firstName = :firstname)", forceFieldsQuery = true)
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedParameterAndTemplateDomainEntityVariable(@Param("firstname") String val);
+
+    @Query(value = "firstName = ?#{sampleExtension.transformParam(#firstname)}")
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedParameterWithSpELExtension(@Param("firstname") String val);
+
+    /** */
     public List<Person> findByFirstNameContaining(String val);
 
     /** */
@@ -65,7 +95,7 @@ public interface PersonRepository extends IgniteRepository<Person, Integer> {
     public Cache.Entry<Integer, Person> findTopBySecondNameLike(String val);
 
     /** */
-    public Person findTopBySecondNameStartingWith(String val);
+    public PersonProjection findTopBySecondNameStartingWith(String val);
 
     /** */
     @Query("firstName = ?")
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryOtherIgniteInstance.java
similarity index 73%
copy from modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
copy to modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryOtherIgniteInstance.java
index 0b9d4df..ac6231b 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryOtherIgniteInstance.java
@@ -1,3 +1,4 @@
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,22 +20,46 @@ package org.apache.ignite.springdata.misc;
 
 import java.util.Collection;
 import java.util.List;
+
 import javax.cache.Cache;
 import org.apache.ignite.springdata20.repository.IgniteRepository;
 import org.apache.ignite.springdata20.repository.config.Query;
 import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
+import org.springframework.data.repository.query.Param;
 
 /**
- * Test repository.
+ *
  */
-@RepositoryConfig(cacheName = "PersonCache")
-public interface PersonRepository extends IgniteRepository<Person, Integer> {
+@RepositoryConfig(igniteInstance = "igniteInstanceTWO", cacheName = "PersonCache")
+public interface PersonRepositoryOtherIgniteInstance extends IgniteRepository<Person, Integer> {
     /** */
     public List<Person> findByFirstName(String val);
 
     /** */
+    @Query("firstName = ?")
+    public List<PersonProjection> queryByFirstNameWithProjection(String val);
+
+    /** */
+    @Query("firstName = :firstname")
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedParameter(@Param("firstname") String val);
+
+    /** */
+    @Query("firstName = ?#{[1]}")
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedIndexedParameter(@Param("notUsed") String notUsed, @Param("firstname") String val);
+
+    /** */
+    @Query(textQuery = true, value = "#{#firstname}", limit = 2)
+    public List<PersonProjection> textQueryByFirstNameWithProjectionNamedParameter(@Param("firstname") String val);
+
+    @Query(value = "select * from (sElecT * from #{#entityName} where firstName = :firstname)", forceFieldsQuery = true)
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedParameterAndTemplateDomainEntityVariable(@Param("firstname") String val);
+
+    @Query(value = "firstName = ?#{sampleExtension.transformParam(#firstname)}")
+    public List<PersonProjection> queryByFirstNameWithProjectionNamedParameterWithSpELExtension(@Param("firstname") String val);
+
+    /** */
     public List<Person> findByFirstNameContaining(String val);
 
     /** */
@@ -65,7 +90,7 @@ public interface PersonRepository extends IgniteRepository<Person, Integer> {
     public Cache.Entry<Integer, Person> findTopBySecondNameLike(String val);
 
     /** */
-    public Person findTopBySecondNameStartingWith(String val);
+    public PersonProjection findTopBySecondNameStartingWith(String val);
 
     /** */
     @Query("firstName = ?")
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
index 156bbb3..bf77597 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepositoryWithCompoundKey.java
@@ -23,6 +23,6 @@ import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
 /**
  * Test repository.
  */
-@RepositoryConfig(cacheName = "PersonWithKeyCache")
+@RepositoryConfig(cacheName = "PersonWithKeyCache", autoCreateCache = true)
 public interface PersonRepositoryWithCompoundKey extends IgniteRepository<Person, PersonKey> {
 }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
new file mode 100644
index 0000000..0e6356a
--- /dev/null
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *      http://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 org.apache.ignite.springdata.misc;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.data.repository.query.spi.EvaluationContextExtensionSupport;
+
+/**
+ * Sample EvaluationContext Extension for Spring Data 2.0
+ * <p>
+ * Use SpEl expressions into your {@code @Query} definitions.
+ * <p>
+ * First, you need to register your extension into your spring data configuration. Sample:
+ * <pre>
+ * {@code @Configuration}
+ * {@code @EnableIgniteRepositories}(basePackages = ... )
+ * public class MyIgniteRepoConfig {
+ * ...
+ *      {@code @Bean}
+ *      public EvaluationContextExtension sampleSpELExtension() {
+ *          return new SampleEvaluationContextExtension();
+ *      }
+ * ...
+ * }
+ * </pre>
+ *
+ * <p>
+ * Sample of usage into your {@code @Query} definitions:
+ * <pre>
+ * {@code @RepositoryConfig}(cacheName = "users")
+ * public interface UserRepository
+ * extends IgniteRepository<User, UUID>{
+ *     [...]
+ *
+ *     {@code @Query}(value = "SELECT * from #{#entityName} where email = ?#{sampleExtension.transformParam(#email)}")
+ *     User searchUserByEmail(@Param("email") String email);
+ *
+ *      [...]
+ *     }
+ * </pre>
+ * <p>
+ *
+ * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
+ */
+public class SampleEvaluationContextExtension extends EvaluationContextExtensionSupport {
+
+    private static final SamplePassParamExtension SAMPLE_PASS_PARAM_EXTENSION_INSTANCE = new SamplePassParamExtension();
+
+    private static final Map<String, Object> properties = new HashMap<>();
+
+    private static final String SAMPLE_EXTENSION_SPEL_VAR = "sampleExtension";
+
+    static {
+        properties.put(SAMPLE_EXTENSION_SPEL_VAR, SAMPLE_PASS_PARAM_EXTENSION_INSTANCE);
+    }
+
+    @Override public String getExtensionId() {
+        return "HK-SAMPLE-PASS-PARAM-EXTENSION";
+    }
+
+    @Override public Map<String, Object> getProperties() {
+        return properties;
+    }
+
+    public static class SamplePassParamExtension {
+
+        // just return same param
+        public Object transformParam(Object param) {
+            return param;
+        }
+
+    }
+
+}
diff --git a/modules/spring-data-2.2/README.txt b/modules/spring-data-2.2/README.txt
index b279dfa..5be6660 100644
--- a/modules/spring-data-2.2/README.txt
+++ b/modules/spring-data-2.2/README.txt
@@ -7,6 +7,21 @@ To enable Spring Data 2.2 module when starting a standalone node, move 'optional
 'libs' folder before running 'ignite.{sh|bat}' script. The content of the module folder will
 be added to classpath in this case.
 
+Main features:
+
+- Supports multiple Ignite instances on same JVM (@RepositoryConfig).
+- Supports query tuning parameters in @Query annotation
+- Supports projections
+- Supports Page and Stream responses
+- Supports Sql Fields Query resultset transformation into the domain entity
+- Supports named parameters (:myParam) into SQL queries, declared using @Param("myParam")
+- Supports advanced parameter binding and SpEL expressions into SQL queries:
+- Template variables:
+    - #entityName - the simple class name of the domain entity
+- Method parameter expressions: Parameters are exposed for indexed access ([0] is the first query method's param) or via the name declared using @Param. The actual SpEL expression binding is triggered by ?#. Example: ?#{[0] or ?#{#myParamName}
+- Advanced SpEL expressions: While advanced parameter binding is a very useful feature, the real power of SpEL stems from the fact, that the expressions can refer to framework abstractions or other application components through SpEL EvaluationContext extension model.
+- Supports SpEL expressions into Text queries (TextQuery).
+
 Importing Spring Data 2.2 Module In Maven Project
 ----------------------------------------
 
diff --git a/modules/spring-data-2.2/pom.xml b/modules/spring-data-2.2/pom.xml
index 404286e..cebd0df 100644
--- a/modules/spring-data-2.2/pom.xml
+++ b/modules/spring-data-2.2/pom.xml
@@ -130,6 +130,12 @@
         </dependency>
 
         <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>${commons.lang.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.ignite</groupId>
             <artifactId>ignite-core</artifactId>
             <version>${project.version}</version>
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java
index 381760c..b81992e 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java
@@ -18,41 +18,92 @@ package org.apache.ignite.springdata22.repository;
 
 import java.io.Serializable;
 import java.util.Map;
+import javax.cache.expiry.ExpiryPolicy;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
 import org.springframework.data.repository.CrudRepository;
+import org.springframework.lang.Nullable;
 
 /**
  * Apache Ignite repository that extends basic capabilities of {@link CrudRepository}.
+ *
+ * @param <V> the cache value type
+ * @param <K> the cache key type
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
-public interface IgniteRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
+public interface IgniteRepository<V, K extends Serializable> extends CrudRepository<V, K> {
+    /**
+     * Returns the Ignite instance bound to the repository
+     *
+     * @return the Ignite instance bound to the repository
+     */
+    public Ignite ignite();
+
+    /**
+     * Returns the Ignite Cache bound to the repository
+     *
+     * @return the Ignite Cache bound to the repository
+     */
+    public IgniteCache<K, V> cache();
+
     /**
      * Saves a given entity using provided key.
      * </p>
-     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates
-     * IDs (keys) that are not unique cluster wide.
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
      *
-     * @param key Entity's key.
+     * @param <S>    Entity type.
+     * @param key    Entity's key.
      * @param entity Entity to save.
-     * @param <S> Entity type.
      * @return Saved entity.
      */
-    <S extends T> S save(ID key, S entity);
+    public <S extends V> S save(K key, S entity);
 
     /**
      * Saves all given keys and entities combinations.
      * </p>
-     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates
-     * IDs (keys) that are not unique cluster wide.
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
      *
+     * @param <S>      type of entities.
      * @param entities Map of key-entities pairs to save.
-     * @param <S> type of entities.
      * @return Saved entities.
      */
-    <S extends T> Iterable<S> save(Map<ID, S> entities);
+    public <S extends V> Iterable<S> save(Map<K, S> entities);
+
+    /**
+     * Saves a given entity using provided key with expiry policy
+     * </p>
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
+     *
+     * @param <S>       Entity type.
+     * @param key       Entity's key.
+     * @param entity    Entity to save.
+     * @param expiryPlc ExpiryPolicy to apply, if not null.
+     * @return Saved entity.
+     */
+    public <S extends V> S save(K key, S entity, @Nullable ExpiryPolicy expiryPlc);
+
+    /**
+     * Saves all given keys and entities combinations with expiry policy
+     * </p>
+     * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
+     * (keys) that are not unique cluster wide.
+     *
+     * @param <S>       type of entities.
+     * @param entities  Map of key-entities pairs to save.
+     * @param expiryPlc ExpiryPolicy to apply, if not null.
+     * @return Saved entities.
+     */
+    public <S extends V> Iterable<S> save(Map<K, S> entities, @Nullable ExpiryPolicy expiryPlc);
 
     /**
      * Deletes all the entities for the provided ids.
      *
      * @param ids List of ids to delete.
      */
-    void deleteAllById(Iterable<ID> ids);
+    public void deleteAllById(Iterable<K> ids);
+
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java
new file mode 100644
index 0000000..eed1b4d
--- /dev/null
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java
@@ -0,0 +1,401 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *      http://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 org.apache.ignite.springdata22.repository.config;
+
+/**
+ * Runtime Dynamic query configuration.
+ * <p>
+ * Can be used as special repository method parameter to provide at runtime:
+ * <ol>
+ * <li>Dynamic query string (requires {@link Query#dynamicQuery()} == true)
+ * <li>Ignite query tuning*
+ * </ol>
+ * <p>
+ * * Please, note that {@link Query} annotation parameters will be ignored in favor of those defined in
+ * {@link DynamicQueryConfig} parameter if present.
+ *
+ * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
+ */
+public class DynamicQueryConfig {
+    /**
+     * Value.
+     */
+    private String value = "";
+
+    /**
+     * Text query.
+     */
+    private boolean textQuery;
+
+    /**
+     * Force fields query.
+     */
+    private boolean forceFieldsQry;
+
+    /**
+     * Collocated.
+     */
+    private boolean collocated;
+
+    /**
+     * Timeout.
+     */
+    private int timeout;
+
+    /**
+     * Enforce join order.
+     */
+    private boolean enforceJoinOrder;
+
+    /**
+     * Distributed joins.
+     */
+    private boolean distributedJoins;
+
+    /**
+     * Replicated only.
+     */
+    private boolean replicatedOnly;
+
+    /**
+     * Lazy.
+     */
+    private boolean lazy;
+
+    /**
+     * Local.
+     */
+    private boolean local;
+
+    /**
+     * Parts.
+     */
+    private int[] parts;
+
+    /**
+     * Limit.
+     */
+    private int limit;
+
+    /**
+     * From Query annotation.
+     *
+     * @param queryConfiguration the query configuration
+     * @return the dynamic query config
+     */
+    public static DynamicQueryConfig fromQueryAnnotation(Query queryConfiguration) {
+        DynamicQueryConfig config = new DynamicQueryConfig();
+        if (queryConfiguration != null) {
+            config.value = queryConfiguration.value();
+            config.collocated = queryConfiguration.collocated();
+            config.timeout = queryConfiguration.timeout();
+            config.enforceJoinOrder = queryConfiguration.enforceJoinOrder();
+            config.distributedJoins = queryConfiguration.distributedJoins();
+            config.replicatedOnly = queryConfiguration.replicatedOnly();
+            config.lazy = queryConfiguration.lazy();
+            config.parts = queryConfiguration.parts();
+            config.local = queryConfiguration.local();
+            config.limit = queryConfiguration.limit();
+        }
+        return config;
+    }
+
+    /**
+     * Query text string.
+     *
+     * @return the string
+     */
+    public String value() {
+        return value;
+    }
+
+    /**
+     * Whether must use TextQuery search.
+     *
+     * @return the boolean
+     */
+    public boolean textQuery() {
+        return textQuery;
+    }
+
+    /**
+     * Force SqlFieldsQuery type, deactivating auto-detection based on SELECT statement. Useful for non SELECT
+     * statements or to not return hidden fields on SELECT * statements.
+     *
+     * @return the boolean
+     */
+    public boolean forceFieldsQuery() {
+        return forceFieldsQry;
+    }
+
+    /**
+     * Sets flag defining if this query is collocated.
+     * <p>
+     * Collocation flag is used for optimization purposes of queries with GROUP BY statements. Whenever Ignite executes
+     * a distributed query, it sends sub-queries to individual cluster members. If you know in advance that the elements
+     * of your query selection are collocated together on the same node and you group by collocated key (primary or
+     * affinity key), then Ignite can make significant performance and network optimizations by grouping data on remote
+     * nodes.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     *
+     * @return the boolean
+     */
+    public boolean collocated() {
+        return collocated;
+    }
+
+    /**
+     * Query timeout in millis. Sets the query execution timeout. Query will be automatically cancelled if the execution
+     * timeout is exceeded. Zero value disables timeout
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the int
+     */
+    public int timeout() {
+        return timeout;
+    }
+
+    /**
+     * Sets flag to enforce join order of tables in the query. If set to {@code true} query optimizer will not reorder
+     * tables in join. By default is {@code false}.
+     * <p>
+     * It is not recommended to enable this property until you are sure that your indexes and the query itself are
+     * correct and tuned as much as possible but query optimizer still produces wrong join order.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     *
+     * @return the boolean
+     */
+    public boolean enforceJoinOrder() {
+        return enforceJoinOrder;
+    }
+
+    /**
+     * Specify if distributed joins are enabled for this query.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the boolean
+     */
+    public boolean distributedJoins() {
+        return distributedJoins;
+    }
+
+    /**
+     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the boolean
+     * @deprecated No longer used as of Apache Ignite 2.8.
+     */
+    @Deprecated
+    public boolean replicatedOnly() {
+        return replicatedOnly;
+    }
+
+    /**
+     * Sets lazy query execution flag.
+     * <p>
+     * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
+     * medium result sets this provides optimal performance and minimize duration of internal database locks, thus
+     * increasing concurrency.
+     * <p>
+     * If result set is too big to fit in available memory this could lead to excessive GC pauses and even
+     * OutOfMemoryError. Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory
+     * consumption at the cost of moderate performance hit.
+     * <p>
+     * Defaults to {@code false}, meaning that the whole result set is fetched to memory eagerly.
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     *
+     * @return the boolean
+     */
+    public boolean lazy() {
+        return lazy;
+    }
+
+    /**
+     * Sets whether this query should be executed on local node only.
+     *
+     * @return the boolean
+     */
+    public boolean local() {
+        return local;
+    }
+
+    /**
+     * Sets partitions for a query. The query will be executed only on nodes which are primary for specified
+     * partitions.
+     * <p>
+     * Note what passed array'll be sorted in place for performance reasons, if it wasn't sorted yet.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @return the int [ ]
+     */
+    public int[] parts() {
+        return parts;
+    }
+
+    /**
+     * Gets limit to response records count for TextQuery. If 0 or less, considered to be no limit.
+     *
+     * @return Limit value.
+     */
+    public int limit() {
+        return limit;
+    }
+
+    /**
+     * Sets value.
+     *
+     * @param value the value
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setValue(String value) {
+        this.value = value;
+        return this;
+    }
+
+    /**
+     * Sets text query.
+     *
+     * @param textQuery the text query
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setTextQuery(boolean textQuery) {
+        this.textQuery = textQuery;
+        return this;
+    }
+
+    /**
+     * Sets force fields query.
+     *
+     * @param forceFieldsQuery the force fields query
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setForceFieldsQuery(boolean forceFieldsQuery) {
+        forceFieldsQry = forceFieldsQuery;
+        return this;
+    }
+
+    /**
+     * Sets collocated.
+     *
+     * @param collocated the collocated
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setCollocated(boolean collocated) {
+        this.collocated = collocated;
+        return this;
+    }
+
+    /**
+     * Sets timeout.
+     *
+     * @param timeout the timeout
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setTimeout(int timeout) {
+        this.timeout = timeout;
+        return this;
+    }
+
+    /**
+     * Sets enforce join order.
+     *
+     * @param enforceJoinOrder the enforce join order
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setEnforceJoinOrder(boolean enforceJoinOrder) {
+        this.enforceJoinOrder = enforceJoinOrder;
+        return this;
+    }
+
+    /**
+     * Sets distributed joins.
+     *
+     * @param distributedJoins the distributed joins
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setDistributedJoins(boolean distributedJoins) {
+        this.distributedJoins = distributedJoins;
+        return this;
+    }
+
+    /**
+     * Sets replicated only.
+     *
+     * @param replicatedOnly the replicated only
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setReplicatedOnly(boolean replicatedOnly) {
+        this.replicatedOnly = replicatedOnly;
+        return this;
+    }
+
+    /**
+     * Sets lazy.
+     *
+     * @param lazy the lazy
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setLazy(boolean lazy) {
+        this.lazy = lazy;
+        return this;
+    }
+
+    /**
+     * Sets local.
+     *
+     * @param local the local
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setLocal(boolean local) {
+        this.local = local;
+        return this;
+    }
+
+    /**
+     * Sets parts.
+     *
+     * @param parts the parts
+     * @return this for chaining
+     */
+    public DynamicQueryConfig setParts(int[] parts) {
+        this.parts = parts;
+        return this;
+    }
+
+    /**
+     * Sets limit to response records count for TextQuery.
+     *
+     * @param limit If 0 or less, considered to be no limit.
+     * @return {@code this} For chaining.
+     */
+    public DynamicQueryConfig setLimit(int limit) {
+        this.limit = limit;
+        return this;
+    }
+
+}
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
index 6888cb0..d789648 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
@@ -22,6 +22,7 @@ import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+
 import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactoryBean;
 import org.apache.ignite.springdata22.repository.support.IgniteRepositoryImpl;
 import org.springframework.beans.factory.FactoryBean;
@@ -41,9 +42,8 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
 @Import(IgniteRepositoriesRegistar.class)
 public @interface EnableIgniteRepositories {
     /**
-     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
-     * {@code @EnableIgniteRepositories("org.my.pkg")} instead of
-     * {@code @EnableIgniteRepositories(basePackages="org.my.pkg")}.
+     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: {@code
+     * @EnableIgniteRepositories("org.my.pkg")} instead of {@code @EnableIgniteRepositories(basePackages="org.my.pkg")}.
      */
     String[] value() default {};
 
@@ -97,8 +97,8 @@ public @interface EnableIgniteRepositories {
     Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
 
     /**
-     * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to
-     * {@link IgniteRepositoryFactoryBean}.
+     * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to {@link
+     * IgniteRepositoryFactoryBean}.
      *
      * @return {@link FactoryBean} class to be used for each repository instance.
      */
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java
index 4e6cf3b..416ec0b 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java
@@ -17,6 +17,7 @@
 package org.apache.ignite.springdata22.repository.config;
 
 import java.lang.annotation.Annotation;
+
 import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
 import org.springframework.data.repository.config.RepositoryConfigurationExtension;
 
@@ -24,12 +25,16 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryBeanDefinitionRegistrarSupport}.
  */
 public class IgniteRepositoriesRegistar extends RepositoryBeanDefinitionRegistrarSupport {
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected Class<? extends Annotation> getAnnotation() {
         return EnableIgniteRepositories.class;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected RepositoryConfigurationExtension getExtension() {
         return new IgniteRepositoryConfigurationExtension();
     }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
index 2831302..b78811b 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -27,23 +27,31 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override public String getModuleName() {
         return "Apache Ignite";
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected String getModulePrefix() {
         return "ignite";
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override public String getRepositoryFactoryBeanClassName() {
         return IgniteRepositoryFactoryBean.class.getName();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
-        return Collections.<Class<?>>singleton(IgniteRepository.class);
+        return Collections.singleton(IgniteRepository.class);
     }
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java
index dacb033..a3b3a51 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.springdata22.repository.config;
 
 import java.lang.annotation.Documented;
@@ -24,14 +23,125 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Annotation to provide a user defined SQL query for a method.
+ * Annotation to provide a user defined query for a method.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface Query {
     /**
-     * SQL query text string.
+     * Query text string. If not provided, Ignite query generator for Spring Data framework will be used to generate one
+     * (only if textQuery = false (default))
      */
     String value() default "";
+
+    /**
+     * Whether annotated repository method must use TextQuery search.
+     */
+    boolean textQuery() default false;
+
+    /**
+     * Force SqlFieldsQuery type, deactivating auto-detection based on SELECT statement. Useful for non SELECT
+     * statements or to not return hidden fields on SELECT * statements.
+     */
+    boolean forceFieldsQuery() default false;
+
+    /**
+     * Sets flag defining if this query is collocated.
+     * <p>
+     * Collocation flag is used for optimization purposes of queries with GROUP BY statements. Whenever Ignite executes
+     * a distributed query, it sends sub-queries to individual cluster members. If you know in advance that the elements
+     * of your query selection are collocated together on the same node and you group by collocated key (primary or
+     * affinity key), then Ignite can make significant performance and network optimizations by grouping data on remote
+     * nodes.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     */
+    boolean collocated() default false;
+
+    /**
+     * Query timeout in millis. Sets the query execution timeout. Query will be automatically cancelled if the execution
+     * timeout is exceeded. Zero value disables timeout
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     */
+    int timeout() default 0;
+
+    /**
+     * Sets flag to enforce join order of tables in the query. If set to {@code true} query optimizer will not reorder
+     * tables in join. By default is {@code false}.
+     * <p>
+     * It is not recommended to enable this property until you are sure that your indexes and the query itself are
+     * correct and tuned as much as possible but query optimizer still produces wrong join order.
+     *
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     */
+    boolean enforceJoinOrder() default false;
+
+    /**
+     * Specify if distributed joins are enabled for this query.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     */
+    boolean distributedJoins() default false;
+
+    /**
+     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     *
+     * @deprecated No longer used as of Apache Ignite 2.8.
+     */
+    @Deprecated
+    boolean replicatedOnly() default false;
+
+    /**
+     * Sets lazy query execution flag.
+     * <p>
+     * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
+     * medium result sets this provides optimal performance and minimize duration of internal database locks, thus
+     * increasing concurrency.
+     * <p>
+     * If result set is too big to fit in available memory this could lead to excessive GC pauses and even
+     * OutOfMemoryError. Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory
+     * consumption at the cost of moderate performance hit.
+     * <p>
+     * Defaults to {@code false}, meaning that the whole result set is fetched to memory eagerly.
+     * <p>
+     * Only applicable to SqlFieldsQuery
+     */
+    boolean lazy() default false;
+
+    /**
+     * Sets whether this query should be executed on local node only.
+     */
+    boolean local() default false;
+
+    /**
+     * Sets partitions for a query. The query will be executed only on nodes which are primary for specified
+     * partitions.
+     * <p>
+     * Note what passed array'll be sorted in place for performance reasons, if it wasn't sorted yet.
+     * <p>
+     * Only applicable to SqlFieldsQuery and SqlQuery
+     */
+    int[] parts() default {};
+
+    /**
+     * Specify whether the annotated method must provide a non null {@link DynamicQueryConfig} parameter with a non
+     * empty value (query string) or {@link DynamicQueryConfig#textQuery()} == true.
+     * <p>
+     * Please, note that  {@link DynamicQueryConfig#textQuery()} annotation parameters will be ignored in favor of those
+     * defined in {@link DynamicQueryConfig} parameter if present (runtime ignite query tuning).
+     */
+    boolean dynamicQuery() default false;
+
+    /**
+     * Sets limit to response records count for TextQuery. If 0 or less, considered to be no limit.
+     */
+    int limit() default 0;
+
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/RepositoryConfig.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/RepositoryConfig.java
index ca3a373..6699ed6 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/RepositoryConfig.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/RepositoryConfig.java
@@ -24,8 +24,14 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
+
 /**
  * The annotation can be used to pass Ignite specific parameters to a bound repository.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
@@ -33,7 +39,39 @@ import java.lang.annotation.Target;
 @Inherited
 public @interface RepositoryConfig {
     /**
+     * Cache name string.
+     *
      * @return A name of a distributed Apache Ignite cache an annotated repository will be mapped to.
      */
     String cacheName() default "";
+
+    /**
+     * Ignite instance string. Default "igniteInstance".
+     *
+     * @return {@link Ignite} instance spring bean name
+     */
+    String igniteInstance() default "igniteInstance";
+
+    /**
+     * Ignite cfg string. Default "igniteCfg".
+     *
+     * @return {@link IgniteConfiguration} spring bean name
+     */
+    String igniteCfg() default "igniteCfg";
+
+    /**
+     * Ignite spring cfg path string. Default "igniteSpringCfgPath".
+     *
+     * @return A path to Ignite's Spring XML configuration spring bean name
+     */
+    String igniteSpringCfgPath() default "igniteSpringCfgPath";
+
+    /**
+     * Auto create cache. Default false to enforce control over cache creation and to avoid cache creation by mistake
+     * <p>
+     * Tells to Ignite Repository factory wether cache should be auto created if not exists.
+     *
+     * @return the boolean
+     */
+    boolean autoCreateCache() default false;
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java
new file mode 100644
index 0000000..e6ad7ba
--- /dev/null
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata22.repository.query;
+
+import java.util.List;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StringUtils;
+
+/**
+ * A wrapper for a String representation of a query offering information about the query.
+ *
+ * @author Jens Schauder
+ * @since 2.0.3
+ */
+interface DeclaredQuery {
+    /**
+     * Creates a {@literal DeclaredQuery} from a query {@literal String}.
+     *
+     * @param qry might be {@literal null} or empty.
+     * @return a {@literal DeclaredQuery} instance even for a {@literal null} or empty argument.
+     */
+    public static DeclaredQuery of(@Nullable String qry) {
+        return StringUtils.isEmpty(qry) ? EmptyDeclaredQuery.EMPTY_QUERY : new StringQuery(qry);
+    }
+
+    /**
+     * @return whether the underlying query has at least one named parameter.
+     */
+    public boolean hasNamedParameter();
+
+    /**
+     * Returns the query string.
+     */
+    public String getQueryString();
+
+    /**
+     * Returns the main alias used in the query.
+     *
+     * @return the alias
+     */
+    @Nullable
+    public String getAlias();
+
+    /**
+     * Returns whether the query is using a constructor expression.
+     *
+     * @since 1.10
+     */
+    public boolean hasConstructorExpression();
+
+    /**
+     * Returns whether the query uses the default projection, i.e. returns the main alias defined for the query.
+     */
+    public boolean isDefaultProjection();
+
+    /**
+     * Returns the {@link StringQuery.ParameterBinding}s registered.
+     */
+    public List<StringQuery.ParameterBinding> getParameterBindings();
+
+    /**
+     * Creates a new {@literal DeclaredQuery} representing a count query, i.e. a query returning the number of rows to
+     * be expected from the original query, either derived from the query wrapped by this instance or from the
+     * information passed as arguments.
+     *
+     * @param cntQry           an optional query string to be used if present.
+     * @param cntQryProjection an optional return type for the query.
+     * @return a new {@literal DeclaredQuery} instance.
+     */
+    public DeclaredQuery deriveCountQuery(@Nullable String cntQry, @Nullable String cntQryProjection);
+
+    /**
+     * @return whether paging is implemented in the query itself, e.g. using SpEL expressions.
+     * @since 2.0.6
+     */
+    public default boolean usesPaging() {
+        return false;
+    }
+
+    /**
+     * Returns whether the query uses JDBC style parameters, i.e. parameters denoted by a simple ? without any index or
+     * name.
+     *
+     * @return Whether the query uses JDBC style parameters.
+     * @since 2.0.6
+     */
+    public boolean usesJdbcStyleParameters();
+}
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java
new file mode 100644
index 0000000..dcf06b4
--- /dev/null
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata22.repository.query;
+
+import java.util.Collections;
+import java.util.List;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * NULL-Object pattern implementation for {@link DeclaredQuery}.
+ *
+ * @author Jens Schauder
+ * @since 2.0.3
+ */
+class EmptyDeclaredQuery implements DeclaredQuery {
+    /**
+     * An implementation implementing the NULL-Object pattern for situations where there is no query.
+     */
+    static final DeclaredQuery EMPTY_QUERY = new EmptyDeclaredQuery();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean hasNamedParameter() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String getQueryString() {
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String getAlias() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean hasConstructorExpression() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean isDefaultProjection() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public List<StringQuery.ParameterBinding> getParameterBindings() {
+        return Collections.emptyList();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public DeclaredQuery deriveCountQuery(@Nullable String cntQry, @Nullable String cntQryProjection) {
+        Assert.hasText(cntQry, "CountQuery must not be empty!");
+        return DeclaredQuery.of(cntQry);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean usesJdbcStyleParameters() {
+        return false;
+    }
+}
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java
new file mode 100644
index 0000000..4e6007a
--- /dev/null
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2013-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata22.repository.query;
+
+import java.util.regex.Pattern;
+import org.springframework.data.repository.core.EntityMetadata;
+import org.springframework.data.repository.core.RepositoryMetadata;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.util.Assert;
+
+/**
+ * Extension of {@link StringQuery} that evaluates the given query string as a SpEL template-expression.
+ * <p>
+ * Currently the following template variables are available:
+ * <ol>
+ * <li>{@code #entityName} - the simple class name of the given entity</li>
+ * <ol>
+ *
+ * @author Thomas Darimont
+ * @author Oliver Gierke
+ * @author Tom Hombergs
+ */
+class ExpressionBasedStringQuery extends StringQuery {
+    /**
+     * Expression parameter.
+     */
+    private static final String EXPRESSION_PARAMETER = "?#{";
+
+    /**
+     * Quoted expression parameter.
+     */
+    private static final String QUOTED_EXPRESSION_PARAMETER = "?__HASH__{";
+
+    /**
+     * Expression parameter quoting.
+     */
+    private static final Pattern EXPRESSION_PARAMETER_QUOTING = Pattern.compile(Pattern.quote(EXPRESSION_PARAMETER));
+
+    /**
+     * Expression parameter unquoting.
+     */
+    private static final Pattern EXPRESSION_PARAMETER_UNQUOTING = Pattern.compile(
+        Pattern.quote(QUOTED_EXPRESSION_PARAMETER));
+
+    /**
+     * Entity name.
+     */
+    private static final String ENTITY_NAME = "entityName";
+
+    /**
+     * Entity name variable.
+     */
+    private static final String ENTITY_NAME_VARIABLE = "#" + ENTITY_NAME;
+
+    /**
+     * Entity name variable expression.
+     */
+    private static final String ENTITY_NAME_VARIABLE_EXPRESSION = "#{" + ENTITY_NAME_VARIABLE + "}";
+
+    /**
+     * Creates a new instance for the given query and {@link EntityMetadata}.
+     *
+     * @param qry      must not be {@literal null} or empty.
+     * @param metadata must not be {@literal null}.
+     * @param parser   must not be {@literal null}.
+     */
+    public ExpressionBasedStringQuery(String qry, RepositoryMetadata metadata, SpelExpressionParser parser) {
+        super(renderQueryIfExpressionOrReturnQuery(qry, metadata, parser));
+    }
+
+    /**
+     * Creates an instance from a given {@link DeclaredQuery}.
+     *
+     * @param qry      the original query. Must not be {@literal null}.
+     * @param metadata the {@link RepositoryMetadata} for the given entity. Must not be {@literal null}.
+     * @param parser   Parser for resolving SpEL expressions. Must not be {@literal null}.
+     * @return A query supporting SpEL expressions.
+     */
+    static ExpressionBasedStringQuery from(DeclaredQuery qry,
+        RepositoryMetadata metadata,
+        SpelExpressionParser parser) {
+        return new ExpressionBasedStringQuery(qry.getQueryString(), metadata, parser);
+    }
+
+    /**
+     * @param qry,     the query expression potentially containing a SpEL expression. Must not be {@literal null}.}
+     * @param metadata the {@link RepositoryMetadata} for the given entity. Must not be {@literal null}.
+     * @param parser   Must not be {@literal null}.
+     * @return rendered query
+     */
+    private static String renderQueryIfExpressionOrReturnQuery(String qry,
+        RepositoryMetadata metadata,
+        SpelExpressionParser parser) {
+
+        Assert.notNull(qry, "query must not be null!");
+        Assert.notNull(metadata, "metadata must not be null!");
+        Assert.notNull(parser, "parser must not be null!");
+
+        if (!containsExpression(qry))
+            return qry;
+
+        StandardEvaluationContext evalCtx = new StandardEvaluationContext();
+        evalCtx.setVariable(ENTITY_NAME, metadata.getDomainType().getSimpleName());
+
+        qry = potentiallyQuoteExpressionsParameter(qry);
+
+        Expression expr = parser.parseExpression(qry, ParserContext.TEMPLATE_EXPRESSION);
+
+        String result = expr.getValue(evalCtx, String.class);
+
+        if (result == null)
+            return qry;
+
+        return potentiallyUnquoteParameterExpressions(result);
+    }
+
+    /**
+     * @param result Result.
+     */
+    private static String potentiallyUnquoteParameterExpressions(String result) {
+        return EXPRESSION_PARAMETER_UNQUOTING.matcher(result).replaceAll(EXPRESSION_PARAMETER);
+    }
+
+    /**
+     * @param qry Query.
+     */
+    private static String potentiallyQuoteExpressionsParameter(String qry) {
+        return EXPRESSION_PARAMETER_QUOTING.matcher(qry).replaceAll(QUOTED_EXPRESSION_PARAMETER);
+    }
+
+    /**
+     * @param qry Query.
+     */
+    private static boolean containsExpression(String qry) {
+        return qry.contains(ENTITY_NAME_VARIABLE_EXPRESSION);
+    }
+
+}
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java
index 4a06a80..5b552af 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java
@@ -17,39 +17,77 @@
 
 package org.apache.ignite.springdata22.repository.query;
 
+import java.util.StringJoiner;
+
 /**
  * Ignite query helper class. For internal use only.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteQuery {
-    /** */
+
+    /**
+     *
+     */
     enum Option {
-        /** Query will be used with Sort object. */
+        /**
+         * Query will be used with Sort object.
+         */
         SORTING,
 
-        /** Query will be used with Pageable object. */
+        /**
+         * Query will be used with Pageable object.
+         */
         PAGINATION,
 
-        /** No advanced option. */
+        /**
+         * No advanced option.
+         */
         NONE
     }
 
-    /** Sql query text string. */
-    private final String sql;
+    /**
+     * Query text string.
+     */
+    private final String qrySql;
 
-    /** */
+    /**
+     * Whether this is a SQL fields query
+     */
     private final boolean isFieldQuery;
 
-    /** Type of option. */
+    /**
+     * Whether this is Text query
+     */
+    private final boolean isTextQuery;
+
+    /**
+     * Whether was autogenerated (by method name)
+     */
+    private final boolean isAutogenerated;
+
+    /**
+     * Type of option.
+     */
     private final Option option;
 
     /**
-     * @param sql Sql.
-     * @param isFieldQuery Is field query.
-     * @param option Option.
+     * @param qrySql          the query string.
+     * @param isFieldQuery    Is field query.
+     * @param isTextQuery     Is a TextQuery
+     * @param isAutogenerated query was autogenerated
+     * @param option          Option.
      */
-    public IgniteQuery(String sql, boolean isFieldQuery, Option option) {
-        this.sql = sql;
+    public IgniteQuery(String qrySql,
+        boolean isFieldQuery,
+        boolean isTextQuery,
+        boolean isAutogenerated,
+        Option option) {
+        this.qrySql = qrySql;
         this.isFieldQuery = isFieldQuery;
+        this.isTextQuery = isTextQuery;
+        this.isAutogenerated = isAutogenerated;
         this.option = option;
     }
 
@@ -58,8 +96,8 @@ public class IgniteQuery {
      *
      * @return SQL query text string.
      */
-    public String sql() {
-        return sql;
+    public String qryStr() {
+        return qrySql;
     }
 
     /**
@@ -72,6 +110,24 @@ public class IgniteQuery {
     }
 
     /**
+     * Returns {@code true} if it's Ignite Text query, {@code false} otherwise.
+     *
+     * @return {@code true} if it's Ignite Text query, {@code false} otherwise.
+     */
+    public boolean isTextQuery() {
+        return isTextQuery;
+    }
+
+    /**
+     * Returns {@code true} if it's autogenerated, {@code false} otherwise.
+     *
+     * @return {@code true} {@code true} if it's autogenerated, {@code false} otherwise.
+     */
+    public boolean isAutogenerated() {
+        return isAutogenerated;
+    }
+
+    /**
      * Advanced querying option.
      *
      * @return querying option.
@@ -79,4 +135,11 @@ public class IgniteQuery {
     public Option options() {
         return option;
     }
+
+    @Override public String toString() {
+        return new StringJoiner(", ", IgniteQuery.class.getSimpleName() + "[", "]").add("qrySql='" + qrySql + "'")
+            .add("isFieldQuery=" + isFieldQuery).add("isTextQuery=" + isTextQuery)
+            .add("isAutogenerated=" + isAutogenerated).add("option=" + option).toString();
+    }
+
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java
index 29a92a8..9772e45 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java
@@ -29,12 +29,17 @@ import org.springframework.data.repository.query.parser.PartTree;
  * Ignite query generator for Spring Data framework.
  */
 public class IgniteQueryGenerator {
+
+    private IgniteQueryGenerator() {
+    }
+
     /**
-     * @param mtd Method.
+     * @param mtd      Method.
      * @param metadata Metadata.
      * @return Generated ignite query.
      */
-    @NotNull public static IgniteQuery generateSql(Method mtd, RepositoryMetadata metadata) {
+    @NotNull
+    public static IgniteQuery generateSql(Method mtd, RepositoryMetadata metadata) {
         PartTree parts = new PartTree(mtd.getName(), metadata.getDomainType());
 
         boolean isCountOrFieldQuery = parts.isCountProjection();
@@ -56,7 +61,7 @@ public class IgniteQueryGenerator {
             if (isCountOrFieldQuery)
                 sql.append("COUNT(1) ");
             else
-                sql.append(" * ");
+                sql.append("* ");
         }
 
         sql.append("FROM ").append(metadata.getDomainType().getSimpleName());
@@ -87,13 +92,13 @@ public class IgniteQueryGenerator {
             sql.append(parts.getMaxResults().intValue());
         }
 
-        return new IgniteQuery(sql.toString(), isCountOrFieldQuery, getOptions(mtd));
+        return new IgniteQuery(sql.toString(), isCountOrFieldQuery, false, true, getOptions(mtd));
     }
 
     /**
      * Add a dynamic part of query for the sorting support.
      *
-     * @param sql SQL text string.
+     * @param sql  SQL text string.
      * @param sort Sort method.
      * @return Sorting criteria in StringBuilder.
      */
@@ -114,6 +119,7 @@ public class IgniteQueryGenerator {
                         case NULLS_LAST:
                             sql.append("LAST");
                             break;
+                        default:
                     }
                 }
                 sql.append(", ");
@@ -128,13 +134,13 @@ public class IgniteQueryGenerator {
     /**
      * Add a dynamic part of a query for the pagination support.
      *
-     * @param sql Builder instance.
+     * @param sql      Builder instance.
      * @param pageable Pageable instance.
      * @return Builder instance.
      */
     public static StringBuilder addPaging(StringBuilder sql, Pageable pageable) {
-        if (pageable.getSort() != null)
-            addSorting(sql, pageable.getSort());
+
+        addSorting(sql, pageable.getSort());
 
         sql.append(" LIMIT ").append(pageable.getPageSize()).append(" OFFSET ").append(pageable.getOffset());
 
@@ -171,7 +177,7 @@ public class IgniteQueryGenerator {
     }
 
     /**
-     * Transform part to sql expression
+     * Transform part to qryStr expression
      */
     private static void handleQueryPart(StringBuilder sql, Part part) {
         sql.append("(");
@@ -212,15 +218,13 @@ public class IgniteQueryGenerator {
             case TRUE:
                 sql.append(" = TRUE");
                 break;
+            //TODO: review this legacy code, LIKE should be -> LIKE ?
+            case LIKE:
             case CONTAINING:
                 sql.append(" LIKE '%' || ? || '%'");
                 break;
             case NOT_CONTAINING:
-                sql.append(" NOT LIKE '%' || ? || '%'");
-                break;
-            case LIKE:
-                sql.append(" LIKE '%' || ? || '%'");
-                break;
+                //TODO: review this legacy code, NOT_LIKE should be -> NOT LIKE ?
             case NOT_LIKE:
                 sql.append(" NOT LIKE '%' || ? || '%'");
                 break;
@@ -249,4 +253,5 @@ public class IgniteQueryGenerator {
 
         sql.append(")");
     }
+
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java
index 9f27a95..c51c984 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java
@@ -20,117 +20,445 @@ package org.apache.ignite.springdata22.repository.query;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.AbstractCollection;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
 import javax.cache.Cache;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.cache.query.TextQuery;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.binary.BinaryUtils;
 import org.apache.ignite.internal.processors.cache.CacheEntryImpl;
+import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
+import org.apache.ignite.internal.processors.cache.binary.IgniteBinaryImpl;
+import org.apache.ignite.internal.processors.cache.query.QueryCursorEx;
+import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.springdata22.repository.config.DynamicQueryConfig;
+import org.apache.ignite.springdata22.repository.query.StringQuery.ParameterBinding;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Slice;
 import org.springframework.data.domain.SliceImpl;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.projection.ProjectionFactory;
 import org.springframework.data.repository.core.RepositoryMetadata;
+import org.springframework.data.repository.query.Parameter;
+import org.springframework.data.repository.query.Parameters;
 import org.springframework.data.repository.query.QueryMethod;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
 import org.springframework.data.repository.query.RepositoryQuery;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.util.StringUtils;
 
-import static org.apache.ignite.springdata22.repository.query.IgniteQueryGenerator.addPaging;
-import static org.apache.ignite.springdata22.repository.query.IgniteQueryGenerator.addSorting;
+import static org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactory.isFieldQuery;
 
 /**
- * Ignite SQL query implementation.
+ * Ignite query implementation.
+ * <p>
+ * <p>
+ * Features:
+ * <ol>
+ * <li> Supports query tuning parameters</li>
+ * <li> Supports projections</li>
+ * <li> Supports Page and Stream responses</li>
+ * <li> Supports SqlFieldsQuery resultset transformation into the domain entity</li>
+ * <li> Supports named parameters (:myParam) into SQL queries, declared using @Param("myParam") annotation</li>
+ * <li> Supports advanced parameter binding and SpEL expressions into SQL queries
+ * <ol>
+ * <li><b>Template variables</b>:
+ * <ol>
+ * <li>{@code #entityName} - the simple class name of the domain entity</li>
+ * </ol>
+ * </li>
+ * <li><b>Method parameter expressions</b>: Parameters are exposed for indexed access ([0] is the first query method's
+ * param) or via the name declared using @Param. The actual SpEL expression binding is triggered by '?#'. Example:
+ * ?#{[0]} or ?#{#myParamName}</li>
+ * <li><b>Advanced SpEL expressions</b>: While advanced parameter binding is a very useful feature, the real power of
+ * SpEL stems from the fact, that the expressions can refer to framework abstractions or other application components
+ * through SpEL EvaluationContext extension model.</li>
+ * </ol>
+ * Examples:
+ * <pre>
+ * {@code @Query}(value = "SELECT * from #{#entityName} where email = :email")
+ * User searchUserByEmail({@code @Param}("email") String email);
+ *
+ * {@code @Query}(value = "SELECT * from #{#entityName} where country = ?#{[0]} and city = ?#{[1]}")
+ * List<User> searchUsersByCity({@code @Param}("country") String country, {@code @Param}("city") String city,
+ * Pageable pageable);
+ *
+ * {@code @Query}(value = "SELECT * from #{#entityName} where email = ?")
+ * User searchUserByEmail(String email);
+ *
+ * {@code @Query}(value = "SELECT * from #{#entityName} where lucene = ?#{
+ * luceneQueryBuilder.search().refresh(true).filter(luceneQueryBuilder.match('city',#city)).build()}")
+ * List<User> searchUsersByCity({@code @Param}("city") String city, Pageable pageable);
+ * </pre>
+ * </li>
+ * <li> Supports SpEL expressions into Text queries ({@link TextQuery}). Examples:
+ * <pre>
+ * {@code @Query}(textQuery = true, value = "email: #{#email}")
+ * User searchUserByEmail({@code @Param}("email") String email);
+ *
+ * {@code @Query}(textQuery = true, value = "#{#textToSearch}")
+ * List<User> searchUsersByText({@code @Param}("textToSearch") String text, Pageable pageable);
+ *
+ * {@code @Query}(textQuery = true, value = "#{[0]}")
+ * List<User> searchUsersByText(String textToSearch, Pageable pageable);
+ *
+ * {@code @Query}(textQuery = true, value = "#{luceneQueryBuilder.search().refresh(true).filter(luceneQueryBuilder
+ * .match('city', #city)).build()}")
+ * List<User> searchUserByCity({@code @Param}("city") String city, Pageable pageable);
+ * </pre>
+ * </li>
+ * <li> Supports dynamic query and tuning at runtime by using {@link DynamicQueryConfig} method parameter. Examples:
+ * <pre>
+ * {@code @Query}(value = "SELECT * from #{#entityName} where email = :email")
+ * User searchUserByEmailWithQueryTuning({@code @Param}("email") String email, {@code @Param}("ignoredUsedAsQueryTuning") DynamicQueryConfig config);
+ *
+ * {@code @Query}(dynamicQuery = true)
+ * List<User> searchUsersByCityWithDynamicQuery({@code @Param}("country") String country, {@code @Param}("city") String city,
+ * {@code @Param}("ignoredUsedAsDynamicQueryAndTuning") DynamicQueryConfig config, Pageable pageable);
+ *
+ * ...
+ * DynamicQueryConfig onlyTunning = new DynamicQueryConfig().setCollocated(true);
+ * repo.searchUserByEmailWithQueryTuning("user@mail.com", onlyTunning);
+ *
+ * DynamicQueryConfig withDynamicQuery = new DynamicQueryConfig().value("SELECT * from #{#entityName} where country = ?#{[0] and city = ?#{[1]}").setForceFieldsQuery(true).setLazy(true).setCollocated(true);
+ * repo.searchUsersByCityWithDynamicQuery("Spain", "Madrid", withDynamicQuery, new PageRequest(0, 100));
+ *
+ * </pre>
+ * </li>
+ * </ol>
+ * <p>
+ * Visit <a href="https://docs.hawkore.com/private/apache-ignite-advanced-indexing">Apache Ignite advanced Indexing
+ * Documentation site</a> for more info about Advanced Lucene Index and Lucene Query Builder.
+ *
+ * @author Apache Ignite Team
+ * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
-@SuppressWarnings({"unchecked", "rawtypes"})
+@SuppressWarnings("unchecked")
 public class IgniteRepositoryQuery implements RepositoryQuery {
-    /** Defines the way how to process query result */
+
+    private static final TreeMap<String, Class<?>> binaryFieldClass = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+    /**
+     * Defines the way how to process query result
+     */
     private enum ReturnStrategy {
-        /** Need to return only one value. */
+        /**
+         * Need to return only one value.
+         */
         ONE_VALUE,
 
-        /** Need to return one cache entry */
+        /**
+         * Need to return one cache entry
+         */
         CACHE_ENTRY,
 
-        /** Need to return list of cache entries */
+        /**
+         * Need to return list of cache entries
+         */
         LIST_OF_CACHE_ENTRIES,
 
-        /** Need to return list of values */
+        /**
+         * Need to return list of values
+         */
         LIST_OF_VALUES,
 
-        /** Need to return list of lists */
+        /**
+         * Need to return list of lists
+         */
         LIST_OF_LISTS,
 
-        /** Need to return slice */
+        /**
+         * Need to return slice
+         */
         SLICE_OF_VALUES,
 
-        /** Slice of cache entries. */
+        /**
+         * Slice of cache entries.
+         */
         SLICE_OF_CACHE_ENTRIES,
 
-        /** Slice of lists. */
-        SLICE_OF_LISTS
+        /**
+         * Slice of lists.
+         */
+        SLICE_OF_LISTS,
+
+        /**
+         * Need to return Page of values
+         */
+        PAGE_OF_VALUES,
+
+        /**
+         * Need to return stream of values
+         */
+        STREAM_OF_VALUES,
     }
 
-    /** Type. */
+    /**
+     * Type.
+     */
     private final Class<?> type;
 
-    /** Sql. */
-    private final IgniteQuery qry;
+    /**
+     * Sql.
+     */
+    private final IgniteQuery staticQuery;
 
-    /** Cache. */
+    /**
+     * Cache.
+     */
     private final IgniteCache cache;
 
-    /** Method. */
+    /**
+     * Ignite instance
+     */
+    private final Ignite ignite;
+
+    /**
+     * required by qryStr field query type for binary manipulation
+     */
+    private IgniteBinaryImpl igniteBinary;
+
+    /**
+     * Ignite bin type.
+     */
+    private BinaryType igniteBinType;
+
+    /**
+     * Method.
+     */
     private final Method mtd;
 
-    /** Metadata. */
+    /**
+     * Metadata.
+     */
     private final RepositoryMetadata metadata;
 
-    /** Factory. */
+    /**
+     * Factory.
+     */
     private final ProjectionFactory factory;
 
-    /** Return strategy. */
-    private final ReturnStrategy returnStgy;
+    /**
+     * Return strategy.
+     */
+    private final ReturnStrategy staticReturnStgy;
 
     /**
-     * @param metadata Metadata.
-     * @param qry Query.
-     * @param mtd Method.
-     * @param factory Factory.
-     * @param cache Cache.
+     * Detect if returned data from method is projected
      */
-    public IgniteRepositoryQuery(RepositoryMetadata metadata, IgniteQuery qry,
-        Method mtd, ProjectionFactory factory, IgniteCache cache) {
-        type = metadata.getDomainType();
-        this.qry = qry;
-        this.cache = cache;
+    private final boolean hasProjection;
+
+    /**
+     * Whether projection is dynamic (provided as method parameter)
+     */
+    private final boolean hasDynamicProjection;
+
+    /**
+     * Dynamic projection parameter index.
+     */
+    private final int dynamicProjectionIndex;
+
+    /**
+     * Dynamic query configuration.
+     */
+    private final int dynamicQueryConfigurationIndex;
+
+    /**
+     * the return query method
+     */
+    private final QueryMethod qMethod;
+
+    /**
+     * the return domain class of QueryMethod
+     */
+    private final Class<?> returnedDomainClass;
+
+    /**
+     * Expression parser.
+     */
+    private final SpelExpressionParser expressionParser;
+
+    /**
+     * could provide ExtensionAwareQueryMethodEvaluationContextProvider
+     */
+    private final QueryMethodEvaluationContextProvider queryMethodEvaluationContextProvider;
+
+    /**
+     * Static query configuration.
+     */
+    private final DynamicQueryConfig staticQueryConfiguration;
+
+    /**
+     * Instantiates a new Ignite repository query.
+     *
+     * @param ignite                               the ignite
+     * @param metadata                             Metadata.
+     * @param staticQuery                          Query.
+     * @param mtd                                  Method.
+     * @param factory                              Factory.
+     * @param cache                                Cache.
+     * @param staticQueryConfiguration             the query configuration
+     * @param queryMethodEvaluationContextProvider the query method evaluation context provider
+     */
+    public IgniteRepositoryQuery(Ignite ignite,
+        RepositoryMetadata metadata,
+        @Nullable IgniteQuery staticQuery,
+        Method mtd,
+        ProjectionFactory factory,
+        IgniteCache cache,
+        @Nullable DynamicQueryConfig staticQueryConfiguration,
+        QueryMethodEvaluationContextProvider queryMethodEvaluationContextProvider) {
         this.metadata = metadata;
         this.mtd = mtd;
         this.factory = factory;
+        type = metadata.getDomainType();
+
+        this.cache = cache;
+        this.ignite = ignite;
+
+        this.staticQueryConfiguration = staticQueryConfiguration;
+        this.staticQuery = staticQuery;
+
+        if (this.staticQuery != null)
+            staticReturnStgy = calcReturnType(mtd, this.staticQuery.isFieldQuery());
+        else
+            staticReturnStgy = null;
+
+        expressionParser = new SpelExpressionParser();
+        this.queryMethodEvaluationContextProvider = queryMethodEvaluationContextProvider;
+
+        qMethod = getQueryMethod();
+
+        // control projection
+        hasDynamicProjection = getQueryMethod().getParameters().hasDynamicProjection();
+        hasProjection = hasDynamicProjection || getQueryMethod().getResultProcessor().getReturnedType()
+            .isProjecting();
+
+        dynamicProjectionIndex = qMethod.getParameters().getDynamicProjectionIndex();
+
+        returnedDomainClass = getQueryMethod().getReturnedObjectType();
 
-        returnStgy = calcReturnType(mtd, qry.isFieldQuery());
+        dynamicQueryConfigurationIndex = getDynamicQueryConfigurationIndex(qMethod);
+
+        // ensure dynamic query configuration param exists if dynamicQuery = true
+        if (dynamicQueryConfigurationIndex == -1 && this.staticQuery == null) {
+            throw new IllegalStateException(
+                "When passing dynamicQuery = true via org.apache.ignite.springdata.repository.config.Query "
+                    + "annotation, you must provide a non null method parameter of type DynamicQueryConfig");
+        }
+        // ensure domain class is registered on marshaller to transform row to entity
+        registerClassOnMarshaller(((IgniteEx)ignite).context(), type);
     }
 
-    /** {@inheritDoc} */
-    @Override public Object execute(Object[] prmtrs) {
-        Query qry = prepareQuery(prmtrs);
+    /**
+     * {@inheritDoc} @param values the values
+     *
+     * @return the object
+     */
+    @Override public Object execute(Object[] values) {
+
+        Object[] parameters = values;
+
+        // config via Query annotation (dynamicQuery = false)
+        DynamicQueryConfig config = staticQueryConfiguration;
 
-        try (QueryCursor qryCursor = cache.query(qry)) {
-            return transformQueryCursor(prmtrs, qryCursor);
+        // or condition to allow query tunning
+        if (config == null || dynamicQueryConfigurationIndex != -1) {
+            DynamicQueryConfig newConfig = (DynamicQueryConfig)values[dynamicQueryConfigurationIndex];
+            parameters = ArrayUtils.removeElement(parameters, dynamicQueryConfigurationIndex);
+            if (newConfig != null) {
+                // upset query configuration
+                config = newConfig;
+            }
+        }
+        // query configuration is required, via Query annotation or per parameter (within provided values param)
+        if (config == null) {
+            throw new IllegalStateException(
+                "Unable to execute query. When passing dynamicQuery = true via org.apache.ignite.springdata"
+                    + ".repository.config.Query annotation, you must provide a non null method parameter of type "
+                    + "DynamicQueryConfig");
         }
+
+        IgniteQuery qry = getQuery(config);
+
+        ReturnStrategy returnStgy = getReturnStgy(qry);
+
+        Query iQry = prepareQuery(qry, config, returnStgy, parameters);
+
+        QueryCursor qryCursor = cache.query(iQry);
+
+        return transformQueryCursor(qry, returnStgy, parameters, qryCursor);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc} @return the query method
+     */
     @Override public QueryMethod getQueryMethod() {
         return new QueryMethod(mtd, metadata, factory);
     }
 
+    private <T extends Parameter> int getDynamicQueryConfigurationIndex(QueryMethod method) {
+        Iterator<T> it = (Iterator<T>)method.getParameters().iterator();
+        int i = 0;
+        boolean found = false;
+        int index = -1;
+        while (it.hasNext()) {
+            T parameter = it.next();
+            if (DynamicQueryConfig.class.isAssignableFrom(parameter.getType())) {
+                if (found) {
+                    throw new IllegalStateException("Invalid '" + method.getName() + "' repository method signature. "
+                        + "Only ONE DynamicQueryConfig parameter is allowed");
+                }
+                found = true;
+                index = i;
+            }
+            i++;
+        }
+        return index;
+    }
+
+    private synchronized IgniteBinaryImpl binary() {
+        if (igniteBinary == null)
+            igniteBinary = (IgniteBinaryImpl)ignite.binary();
+        return igniteBinary;
+    }
+
+    private synchronized BinaryType binType() {
+        if (igniteBinType == null)
+            igniteBinType = binary().type(type);
+        return igniteBinType;
+    }
+
     /**
      * @param mtd Method.
      * @param isFieldQry Is field query.
@@ -139,39 +467,47 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private ReturnStrategy calcReturnType(Method mtd, boolean isFieldQry) {
         Class<?> returnType = mtd.getReturnType();
 
-        if (returnType.isAssignableFrom(ArrayList.class)) {
-            if (isFieldQry) {
-                if (hasAssignableGenericReturnTypeFrom(ArrayList.class, mtd))
-                    return ReturnStrategy.LIST_OF_LISTS;
-            }
-            else if (hasAssignableGenericReturnTypeFrom(Cache.Entry.class, mtd))
-                return ReturnStrategy.LIST_OF_CACHE_ENTRIES;
-
-            return ReturnStrategy.LIST_OF_VALUES;
-        }
-        else if (returnType == Slice.class) {
+        if (returnType == Slice.class) {
             if (isFieldQry) {
                 if (hasAssignableGenericReturnTypeFrom(ArrayList.class, mtd))
                     return ReturnStrategy.SLICE_OF_LISTS;
             }
             else if (hasAssignableGenericReturnTypeFrom(Cache.Entry.class, mtd))
                 return ReturnStrategy.SLICE_OF_CACHE_ENTRIES;
-
             return ReturnStrategy.SLICE_OF_VALUES;
         }
+        else if (returnType == Page.class)
+            return ReturnStrategy.PAGE_OF_VALUES;
+        else if (returnType == Stream.class)
+            return ReturnStrategy.STREAM_OF_VALUES;
         else if (Cache.Entry.class.isAssignableFrom(returnType))
             return ReturnStrategy.CACHE_ENTRY;
+        else if (Iterable.class.isAssignableFrom(returnType)) {
+            if (isFieldQry) {
+                if (hasAssignableGenericReturnTypeFrom(ArrayList.class, mtd))
+                    return ReturnStrategy.LIST_OF_LISTS;
+            }
+            else if (hasAssignableGenericReturnTypeFrom(Cache.Entry.class, mtd))
+                return ReturnStrategy.LIST_OF_CACHE_ENTRIES;
+            return ReturnStrategy.LIST_OF_VALUES;
+        }
         else
             return ReturnStrategy.ONE_VALUE;
     }
 
     /**
-     * @param cls Class 1.
+     * @param cls Class.
      * @param mtd Method.
      * @return if {@code mtd} return type is assignable from {@code cls}
      */
     private boolean hasAssignableGenericReturnTypeFrom(Class<?> cls, Method mtd) {
-        Type[] actualTypeArguments = ((ParameterizedType)mtd.getGenericReturnType()).getActualTypeArguments();
+
+        Type genericReturnType = mtd.getGenericReturnType();
+
+        if (!(genericReturnType instanceof ParameterizedType))
+            return false;
+
+        Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();
 
         if (actualTypeArguments.length == 0)
             return false;
@@ -194,45 +530,140 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     }
 
     /**
-     * @param prmtrs Prmtrs.
-     * @param qryCursor Query cursor.
-     * @return Query cursor or slice
+     * when select fields by query H2 returns Timestamp for types java.util.Date and java.qryStr.Timestamp
+     *
+     * @see org.apache.ignite.internal.processors.query.h2.H2DatabaseType map.put(Timestamp.class, TIMESTAMP)
+     * map.put(java.util.Date.class, TIMESTAMP) map.put(java.qryStr.Date.class, DATE)
      */
-    @Nullable private Object transformQueryCursor(Object[] prmtrs, QueryCursor qryCursor) {
-        if (qry.isFieldQuery()) {
-            Iterable<List> qryIter = (Iterable<List>)qryCursor;
+    private static <T> T fixExpectedType(final Object object, final Class<T> expected) {
+        if (expected != null && object instanceof java.sql.Timestamp && expected.equals(java.util.Date.class))
+            return (T)new java.util.Date(((java.sql.Timestamp)object).getTime());
+        return (T)object;
+    }
 
-            switch (returnStgy) {
-                case LIST_OF_VALUES:
-                    List list = new ArrayList<>();
+    /**
+     * @param cfg Config.
+     */
+    private IgniteQuery getQuery(@Nullable DynamicQueryConfig cfg) {
+        if (staticQuery != null)
+            return staticQuery;
+        if (cfg != null && (StringUtils.hasText(cfg.value()) || cfg.textQuery())) {
+            return new IgniteQuery(cfg.value(),
+                !cfg.textQuery() && (isFieldQuery(cfg.value()) || cfg.forceFieldsQuery()), cfg.textQuery(),
+                false, IgniteQueryGenerator.getOptions(mtd));
+        }
+        throw new IllegalStateException("Unable to obtain a valid query. When passing dynamicQuery = true via org"
+            + ".apache.ignite.springdata.repository.config.Query annotation, you must"
+            + " provide a non null method parameter of type DynamicQueryConfig with a "
+            + "non empty value (query string) or textQuery = true");
+    }
 
-                    for (List entry : qryIter)
-                        list.add(entry.get(0));
+    /**
+     * @param qry Query.
+     */
+    private ReturnStrategy getReturnStgy(IgniteQuery qry) {
+        if (staticReturnStgy != null)
+            return staticReturnStgy;
+        if (qry != null)
+            return calcReturnType(mtd, qry.isFieldQuery());
+        throw new IllegalStateException("Unable to obtain a valid return strategy. When passing dynamicQuery = true "
+            + "via org.apache.ignite.springdata.repository.config.Query annotation, "
+            + "you must provide a non null method parameter of type "
+            + "DynamicQueryConfig with a non empty value (query string) or textQuery "
+            + "= true");
+    }
 
-                    return list;
+    /**
+     * @param cls Class.
+     */
+    private static boolean isPrimitiveOrWrapper(Class<?> cls) {
+        return cls.isPrimitive() ||
+            Boolean.class.equals(cls) ||
+            Byte.class.equals(cls) ||
+            Character.class.equals(cls) ||
+            Short.class.equals(cls) ||
+            Integer.class.equals(cls) ||
+            Long.class.equals(cls) ||
+            Float.class.equals(cls) ||
+            Double.class.equals(cls) ||
+            Void.class.equals(cls) ||
+            String.class.equals(cls) ||
+            UUID.class.equals(cls);
+    }
 
-                case ONE_VALUE:
-                    Iterator<List> iter = qryIter.iterator();
+    /**
+     * @param prmtrs    Prmtrs.
+     * @param qryCursor Query cursor.
+     * @return Query cursor or slice
+     */
+    @Nullable
+    private Object transformQueryCursor(IgniteQuery qry,
+        ReturnStrategy returnStgy,
+        Object[] prmtrs,
+        QueryCursor qryCursor) {
+
+        final Class<?> returnClass;
+
+        if (hasProjection) {
+            if (hasDynamicProjection)
+                returnClass = (Class<?>)prmtrs[dynamicProjectionIndex];
+            else
+                returnClass = returnedDomainClass;
+        }
+        else
+            returnClass = returnedDomainClass;
 
-                    if (iter.hasNext())
-                        return iter.next().get(0);
+        if (qry.isFieldQuery()) {
+            // take control over single primite result from queries, i.e. DELETE, SELECT COUNT, UPDATE ...
+            boolean singlePrimitiveResult = isPrimitiveOrWrapper(returnClass);
 
-                    return null;
+            final List<GridQueryFieldMetadata> meta = ((QueryCursorEx)qryCursor).fieldsMeta();
 
-                case SLICE_OF_VALUES:
-                    List content = new ArrayList<>();
+            Function<List<?>, ?> cWrapperTransformFunction = null;
 
-                    for (List entry : qryIter)
-                        content.add(entry.get(0));
+            if (type.equals(returnClass)) {
+                IgniteBinaryImpl binary = binary();
+                BinaryType binType = binType();
+                cWrapperTransformFunction = row -> rowToEntity(binary, binType, row, meta);
+            }
+            else {
+                if (hasProjection || singlePrimitiveResult) {
+                    if (singlePrimitiveResult)
+                        cWrapperTransformFunction = row -> row.get(0);
+                    else {
+                        // Map row -> projection class
+                        cWrapperTransformFunction = row -> factory
+                            .createProjection(returnClass, rowToMap(row, meta));
+                    }
+                }
+                else
+                    cWrapperTransformFunction = row -> rowToMap(row, meta);
+            }
 
-                    return new SliceImpl(content, (Pageable)prmtrs[prmtrs.length - 1], true);
+            QueryCursorWrapper<?, ?> cWrapper = new QueryCursorWrapper<>((QueryCursor<List<?>>)qryCursor,
+                cWrapperTransformFunction);
 
+            switch (returnStgy) {
+                case PAGE_OF_VALUES:
+                    return new PageImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], 0);
+                case LIST_OF_VALUES:
+                    return cWrapper.getAll();
+                case STREAM_OF_VALUES:
+                    return cWrapper.stream();
+                case ONE_VALUE:
+                    Iterator<?> iter = cWrapper.iterator();
+                    if (iter.hasNext()) {
+                        Object resp = iter.next();
+                        U.closeQuiet(cWrapper);
+                        return resp;
+                    }
+                    return null;
+                case SLICE_OF_VALUES:
+                    return new SliceImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
                 case SLICE_OF_LISTS:
                     return new SliceImpl(qryCursor.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
-
                 case LIST_OF_LISTS:
                     return qryCursor.getAll();
-
                 default:
                     throw new IllegalStateException();
             }
@@ -240,87 +671,444 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         else {
             Iterable<CacheEntryImpl> qryIter = (Iterable<CacheEntryImpl>)qryCursor;
 
-            switch (returnStgy) {
-                case LIST_OF_VALUES:
-                    List list = new ArrayList<>();
+            Function<CacheEntryImpl, ?> cWrapperTransformFunction;
 
-                    for (CacheEntryImpl entry : qryIter)
-                        list.add(entry.getValue());
+            if (hasProjection && !type.equals(returnClass))
+                cWrapperTransformFunction = row -> factory.createProjection(returnClass, row.getValue());
+            else
+                cWrapperTransformFunction = row -> row.getValue();
 
-                    return list;
+            QueryCursorWrapper<?, ?> cWrapper = new QueryCursorWrapper<>((QueryCursor<CacheEntryImpl>)qryCursor,
+                cWrapperTransformFunction);
 
+            switch (returnStgy) {
+                case PAGE_OF_VALUES:
+                    return new PageImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], 0);
+                case LIST_OF_VALUES:
+                    return cWrapper.getAll();
+                case STREAM_OF_VALUES:
+                    return cWrapper.stream();
                 case ONE_VALUE:
-                    Iterator<CacheEntryImpl> iter1 = qryIter.iterator();
+                    Iterator<?> iter1 = cWrapper.iterator();
+                    if (iter1.hasNext()) {
+                        Object resp = iter1.next();
+                        U.closeQuiet(cWrapper);
+                        return resp;
+                    }
+                    return null;
+                case CACHE_ENTRY:
+                    Iterator<?> iter2 = qryIter.iterator();
+                    if (iter2.hasNext()) {
+                        Object resp2 = iter2.next();
+                        U.closeQuiet(qryCursor);
+                        return resp2;
+                    }
+                    return null;
+                case SLICE_OF_VALUES:
+                    return new SliceImpl(cWrapper.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
+                case SLICE_OF_CACHE_ENTRIES:
+                    return new SliceImpl(qryCursor.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
+                case LIST_OF_CACHE_ENTRIES:
+                    return qryCursor.getAll();
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+    }
 
-                    if (iter1.hasNext())
-                        return iter1.next().getValue();
+    /**
+     * Extract bindable values
+     *
+     * @param values            values invoking query method
+     * @param queryMethodParams query method parameter definitions
+     * @param queryBindings     All parameters found on query string that need to be binded
+     * @return new list of parameters
+     */
+    private Object[] extractBindableValues(Object[] values,
+        Parameters<?, ?> queryMethodParams,
+        List<ParameterBinding> queryBindings) {
+
+        // no binding params then exit
+        if (queryBindings.isEmpty())
+            return values;
+
+        Object[] newValues = new Object[queryBindings.size()];
+
+        // map bindable parameters from query method: (index/name) - index
+        HashMap<String, Integer> methodParams = new HashMap<>();
+
+        // create an evaluation context for custom query
+        EvaluationContext queryEvalContext = queryMethodEvaluationContextProvider
+            .getEvaluationContext(queryMethodParams, values);
+
+        // By default queryEvalContext:
+        // - make accesible query method parameters by index:
+        // @Query("select u from User u where u.age = ?#{[0]}")
+        // List<User> findUsersByAge(int age);
+        // - make accesible query method parameters by name:
+        // @Query("select u from User u where u.firstname = ?#{#customer.firstname}")
+        // List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
+
+        // query method param's index by name and position
+        queryMethodParams.getBindableParameters().forEach(p -> {
+            if (p.isNamedParameter()) {
+                // map by name (annotated by @Param)
+                methodParams.put(p.getName().get(), p.getIndex());
+            }
+            // map by position
+            methodParams.put(String.valueOf(p.getIndex()), p.getIndex());
+        });
 
-                    return null;
+        // process all parameters on query and extract new values to bind
+        for (int i = 0; i < queryBindings.size(); i++) {
+            ParameterBinding p = queryBindings.get(i);
 
-                case CACHE_ENTRY:
-                    Iterator<CacheEntryImpl> iter2 = qryIter.iterator();
+            if (p.isExpression()) {
+                // Evaluate SpEl expressions (synthetic parameter value) , example ?#{#customer.firstname}
+                newValues[i] = expressionParser.parseExpression(p.getExpression()).getValue(queryEvalContext);
+            }
+            else {
+                // Extract parameter value by name or position respectively from invoking values
+                newValues[i] = values[methodParams.get(
+                    p.getName() != null ? p.getName() : String.valueOf(p.getRequiredPosition() - 1))];
+            }
+        }
 
-                    if (iter2.hasNext())
-                        return iter2.next();
+        return newValues;
+    }
 
-                    return null;
+    /**
+     * @param qry        Query.
+     * @param config     Config.
+     * @param returnStgy Return stgy.
+     * @param values     Values.
+     * @return prepared query for execution
+     */
+    @NotNull
+    private Query prepareQuery(IgniteQuery qry, DynamicQueryConfig config, ReturnStrategy returnStgy, Object[] values) {
 
-                case SLICE_OF_VALUES:
-                    List content = new ArrayList<>();
+        Object[] parameters = values;
 
-                    for (CacheEntryImpl entry : qryIter)
-                        content.add(entry.getValue());
+        String queryString = qry.qryStr();
 
-                    return new SliceImpl(content, (Pageable)prmtrs[prmtrs.length - 1], true);
+        Query query;
 
-                case SLICE_OF_CACHE_ENTRIES:
-                    return new SliceImpl(qryCursor.getAll(), (Pageable)prmtrs[prmtrs.length - 1], true);
+        checkRequiredPageable(returnStgy, values);
 
-                case LIST_OF_CACHE_ENTRIES:
-                    return qryCursor.getAll();
+        if (!qry.isTextQuery()) {
 
+            if (!qry.isAutogenerated()) {
+                StringQuery squery = new ExpressionBasedStringQuery(queryString, metadata, expressionParser);
+                queryString = squery.getQueryString();
+                parameters = extractBindableValues(parameters, getQueryMethod().getParameters(),
+                    squery.getParameterBindings());
+            }
+            else {
+                // remove dynamic projection from parameters
+                if (hasDynamicProjection)
+                    parameters = ArrayUtils.remove(parameters, dynamicProjectionIndex);
+            }
+
+            switch (qry.options()) {
+                case SORTING:
+                    queryString = IgniteQueryGenerator
+                        .addSorting(new StringBuilder(queryString), (Sort)values[values.length - 1])
+                        .toString();
+                    if (qry.isAutogenerated())
+                        parameters = Arrays.copyOfRange(parameters, 0, values.length - 1);
+                    break;
+                case PAGINATION:
+                    queryString = IgniteQueryGenerator
+                        .addPaging(new StringBuilder(queryString), (Pageable)values[values.length - 1])
+                        .toString();
+                    if (qry.isAutogenerated())
+                        parameters = Arrays.copyOfRange(parameters, 0, values.length - 1);
+                    break;
                 default:
-                    throw new IllegalStateException();
+            }
+
+            if (qry.isFieldQuery()) {
+                SqlFieldsQuery sqlFieldsQry = new SqlFieldsQuery(queryString);
+                sqlFieldsQry.setArgs(parameters);
+
+                sqlFieldsQry.setCollocated(config.collocated());
+                sqlFieldsQry.setDistributedJoins(config.distributedJoins());
+                sqlFieldsQry.setEnforceJoinOrder(config.enforceJoinOrder());
+                sqlFieldsQry.setLazy(config.lazy());
+                sqlFieldsQry.setLocal(config.local());
+
+                if (config.parts() != null && config.parts().length > 0)
+                    sqlFieldsQry.setPartitions(config.parts());
+
+                sqlFieldsQry.setReplicatedOnly(config.replicatedOnly());
+                sqlFieldsQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
+
+                query = sqlFieldsQry;
+            }
+            else {
+                SqlQuery sqlQry = new SqlQuery(type, queryString);
+                sqlQry.setArgs(parameters);
+
+                sqlQry.setDistributedJoins(config.distributedJoins());
+                sqlQry.setLocal(config.local());
+                if (config.parts() != null && config.parts().length > 0)
+                    sqlQry.setPartitions(config.parts());
+                sqlQry.setReplicatedOnly(config.replicatedOnly());
+                sqlQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
+
+                query = sqlQry;
             }
         }
+        else {
+
+            int pageSize = -1;
+
+            switch (qry.options()) {
+                case PAGINATION:
+                    pageSize = ((Pageable)parameters[parameters.length - 1]).getPageSize();
+                    break;
+            }
+
+            // check if queryString contains SpEL template expressions and evaluate them if any
+            if (queryString.contains("#{")) {
+                EvaluationContext queryEvalContext = queryMethodEvaluationContextProvider
+                    .getEvaluationContext(getQueryMethod().getParameters(),
+                        values);
+
+                Object eval = expressionParser.parseExpression(queryString, ParserContext.TEMPLATE_EXPRESSION)
+                    .getValue(queryEvalContext);
+
+                if (!(eval instanceof String)) {
+                    throw new IllegalStateException(
+                        "TextQuery with SpEL expressions must produce a String response, but found " + eval.getClass()
+                            .getName()
+                            + ". Please, check your expression: " + queryString);
+                }
+                queryString = (String)eval;
+            }
+
+            TextQuery textQuery = new TextQuery(type, queryString, config.limit());
+
+            textQuery.setLocal(config.local());
+
+            if (pageSize > -1)
+                textQuery.setPageSize(pageSize);
+
+            query = textQuery;
+        }
+        return query;
+    }
+
+    private static Map<String, Object> rowToMap(final List<?> row, final List<GridQueryFieldMetadata> meta) {
+        // use treemap with case insensitive property name
+        final TreeMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        for (int i = 0; i < meta.size(); i++) {
+            // don't want key or val columns
+            final String metaField = meta.get(i).fieldName().toLowerCase();
+            if (!metaField.equalsIgnoreCase(QueryUtils.KEY_FIELD_NAME) && !metaField.equalsIgnoreCase(
+                QueryUtils.VAL_FIELD_NAME))
+                map.put(metaField, row.get(i));
+        }
+        return map;
+    }
+
+    /*
+     * convert row ( with list of field values) into domain entity
+     */
+    private <V> V rowToEntity(final IgniteBinaryImpl binary,
+        final BinaryType binType,
+        final List<?> row,
+        final List<GridQueryFieldMetadata> meta) {
+        // additional data returned by query not present on domain object type
+        final TreeMap<String, Object> metadata = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        final BinaryObjectBuilder bldr = binary.builder(binType.typeName());
+
+        for (int i = 0; i < row.size(); i++) {
+            final GridQueryFieldMetadata fMeta = meta.get(i);
+            final String metaField = fMeta.fieldName();
+            // add existing entity fields to binary object
+            if (binType.field(fMeta.fieldName()) != null && !metaField.equalsIgnoreCase(QueryUtils.KEY_FIELD_NAME)
+                && !metaField.equalsIgnoreCase(QueryUtils.VAL_FIELD_NAME)) {
+                final Object fieldValue = row.get(i);
+                if (fieldValue != null) {
+                    final Class<?> clazz = getClassForBinaryField(binary, binType, fMeta);
+                    // null values must not be set into binary objects
+                    bldr.setField(metaField, fixExpectedType(fieldValue, clazz));
+                }
+            }
+            else {
+                // don't want key or val column... but wants null values
+                if (!metaField.equalsIgnoreCase(QueryUtils.KEY_FIELD_NAME) && !metaField.equalsIgnoreCase(
+                    QueryUtils.VAL_FIELD_NAME))
+                    metadata.put(metaField, row.get(i));
+            }
+        }
+        return bldr.build().deserialize();
     }
 
     /**
-     * @param prmtrs Prmtrs.
-     * @return prepared query for execution
+     * Obtains real field class from resultset metadata field whether it's available
      */
-    @SuppressWarnings("deprecation")
-    @NotNull private Query prepareQuery(Object[] prmtrs) {
-        Object[] parameters = prmtrs;
-        String sql = qry.sql();
+    private Class<?> getClassForBinaryField(final IgniteBinaryImpl binary,
+        final BinaryType binType,
+        final GridQueryFieldMetadata fieldMeta) {
+        try {
 
-        switch (qry.options()) {
-            case SORTING:
-                sql = addSorting(new StringBuilder(sql), (Sort)parameters[parameters.length - 1]).toString();
-                parameters = Arrays.copyOfRange(parameters, 0, parameters.length - 1);
+            final String fieldId = fieldMeta.schemaName() + "." + fieldMeta.typeName() + "." + fieldMeta.fieldName();
 
-                break;
+            if (binaryFieldClass.containsKey(fieldId))
+                return binaryFieldClass.get(fieldId);
 
-            case PAGINATION:
-                sql = addPaging(new StringBuilder(sql), (Pageable)parameters[parameters.length - 1]).toString();
-                parameters = Arrays.copyOfRange(parameters, 0, parameters.length - 1);
+            Class<?> clazz = null;
 
-                break;
+            synchronized (binaryFieldClass) {
 
-            case NONE:
-                // No-op.
+                if (binaryFieldClass.containsKey(fieldId))
+                    return binaryFieldClass.get(fieldId);
+
+                String fieldName = null;
+
+                // search field name on binary type (query returns case insensitive
+                // field name) but BinaryType is not case insensitive
+                for (final String fname : binType.fieldNames()) {
+                    if (fname.equalsIgnoreCase(fieldMeta.fieldName())) {
+                        fieldName = fname;
+                        break;
+                    }
+                }
+
+                final CacheObjectBinaryProcessorImpl proc = (CacheObjectBinaryProcessorImpl)binary.processor();
+
+                // search for class by typeId, if not found use
+                // fieldMeta.fieldTypeName() class
+                clazz = BinaryUtils.resolveClass(proc.binaryContext(), binary.typeId(binType.fieldTypeName(fieldName)),
+                    fieldMeta.fieldTypeName(), ignite.configuration().getClassLoader(), true);
+
+                binaryFieldClass.put(fieldId, clazz);
+            }
+
+            return clazz;
+        }
+        catch (final Exception e) {
+            return null;
         }
+    }
 
-        if (qry.isFieldQuery()) {
-            SqlFieldsQuery sqlFieldsQry = new SqlFieldsQuery(sql);
-            sqlFieldsQry.setArgs(parameters);
+    /**
+     * Validates operations that requires Pageable parameter
+     *
+     * @param returnStgy Return stgy.
+     * @param prmtrs     Prmtrs.
+     */
+    private void checkRequiredPageable(ReturnStrategy returnStgy, Object[] prmtrs) {
+        try {
+            if (returnStgy == ReturnStrategy.PAGE_OF_VALUES || returnStgy == ReturnStrategy.SLICE_OF_VALUES
+                || returnStgy == ReturnStrategy.SLICE_OF_CACHE_ENTRIES) {
+                Pageable page = (Pageable)prmtrs[prmtrs.length - 1];
+                page.isPaged();
+            }
+        }
+        catch (NullPointerException | IndexOutOfBoundsException | ClassCastException e) {
+            throw new IllegalStateException(
+                "For " + returnStgy.name() + " you must provide on last method parameter a non null Pageable instance");
+        }
+    }
 
-            return sqlFieldsQry;
+    /**
+     * @param ctx   Context.
+     * @param clazz Clazz.
+     */
+    private static void registerClassOnMarshaller(final GridKernalContext ctx, final Class<?> clazz) {
+        try {
+            // ensure class registration for marshaller on cluster...
+            if (!U.isJdk(clazz))
+                U.marshal(ctx, clazz.newInstance());
+        }
+        catch (final Exception ignored) {
+            // silent
+        }
+    }
+
+    /**
+     * Ignite QueryCursor wrapper.
+     * <p>
+     * Ensures closing underline cursor when there is no data.
+     *
+     * @param <T> input type
+     * @param <V> transformed output type
+     */
+    public static class QueryCursorWrapper<T, V> extends AbstractCollection<V> implements QueryCursor<V> {
+
+        /**
+         * Delegate query cursor.
+         */
+        private final QueryCursor<T> delegate;
+
+        /**
+         * Transformer.
+         */
+        private final Function<T, V> transformer;
+
+        /**
+         * Instantiates a new Query cursor wrapper.
+         *
+         * @param delegate    delegate QueryCursor with T input elements
+         * @param transformer Function to transform T to V elements
+         */
+        public QueryCursorWrapper(final QueryCursor<T> delegate, final Function<T, V> transformer) {
+            this.delegate = delegate;
+            this.transformer = transformer;
         }
 
-        SqlQuery sqlQry = new SqlQuery(type, sql);
-        sqlQry.setArgs(parameters);
+        /**
+         * {@inheritDoc} @return the iterator
+         */
+        @Override public Iterator<V> iterator() {
+
+            final Iterator<T> it = delegate.iterator();
+
+            return new Iterator<V>() {
+                @Override public boolean hasNext() {
+                    if (!it.hasNext()) {
+                        U.closeQuiet(delegate);
+                        return false;
+                    }
+                    return true;
+                }
+
+                @Override public V next() {
+                    final V r = transformer.apply(it.next());
+                    if (r != null)
+                        return r;
+                    throw new NoSuchElementException();
+                }
+            };
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override public void close() {
+            U.closeQuiet(delegate);
+        }
+
+        /**
+         * {@inheritDoc} @return the all
+         */
+        @Override public List<V> getAll() {
+            final List<V> data = new ArrayList<>();
+            delegate.forEach(i -> data.add(transformer.apply(i)));
+            U.closeQuiet(delegate);
+            return data;
+        }
+
+        /**
+         * {@inheritDoc} @return the int
+         */
+        @Override public int size() {
+            return 0;
+        }
 
-        return sqlQry;
     }
+
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java
new file mode 100644
index 0000000..3c46aae
--- /dev/null
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2008-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata22.repository.query;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import org.springframework.data.util.Streamable;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import static java.util.regex.Pattern.CASE_INSENSITIVE;
+import static java.util.regex.Pattern.DOTALL;
+import static java.util.regex.Pattern.compile;
+
+/**
+ * Simple utility class to create queries.
+ *
+ * @author Oliver Gierke
+ * @author Kevin Raymond
+ * @author Thomas Darimont
+ * @author Komi Innocent
+ * @author Christoph Strobl
+ * @author Mark Paluch
+ * @author Sébastien Péralta
+ * @author Jens Schauder
+ * @author Nils Borrmann
+ * @author Reda.Housni -Alaoui
+ */
+public abstract class QueryUtils {
+    /**
+     * The constant COUNT_QUERY_STRING.
+     */
+    public static final String COUNT_QUERY_STRING = "select count(%s) from %s x";
+
+    /**
+     * The constant DELETE_ALL_QUERY_STRING.
+     */
+    public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
+
+    /**
+     * Used Regex/Unicode categories (see http://www.unicode.org/reports/tr18/#General_Category_Property): Z Separator
+     * Cc Control Cf Format P Punctuation
+     */
+    private static final String IDENTIFIER = "[._[\\P{Z}&&\\P{Cc}&&\\P{Cf}&&\\P{P}]]+";
+
+    /**
+     * The Colon no double colon.
+     */
+    static final String COLON_NO_DOUBLE_COLON = "(?<![:\\\\]):";
+
+    /**
+     * The Identifier group.
+     */
+    static final String IDENTIFIER_GROUP = String.format("(%s)", IDENTIFIER);
+
+    /** */
+    private static final String COUNT_REPLACEMENT_TEMPLATE = "select count(%s) $5$6$7";
+
+    /** */
+    private static final String SIMPLE_COUNT_VALUE = "$2";
+
+    /** */
+    private static final String COMPLEX_COUNT_VALUE = "$3$6";
+
+    /** */
+    private static final String ORDER_BY_PART = "(?iu)\\s+order\\s+by\\s+.*$";
+
+    /** */
+    private static final Pattern ALIAS_MATCH;
+
+    /** */
+    private static final Pattern COUNT_MATCH;
+
+    /** */
+    private static final Pattern PROJECTION_CLAUSE = Pattern
+        .compile("select\\s+(.+)\\s+from", Pattern.CASE_INSENSITIVE);
+
+    /** */
+    private static final String JOIN = "join\\s+(fetch\\s+)?" + IDENTIFIER + "\\s+(as\\s+)?" + IDENTIFIER_GROUP;
+
+    /** */
+    private static final Pattern JOIN_PATTERN = Pattern.compile(JOIN, Pattern.CASE_INSENSITIVE);
+
+    /** */
+    private static final String EQUALS_CONDITION_STRING = "%s.%s = :%s";
+
+    /** */
+    private static final Pattern NAMED_PARAMETER = Pattern.compile(
+        COLON_NO_DOUBLE_COLON + IDENTIFIER + "|\\#" + IDENTIFIER, CASE_INSENSITIVE);
+
+    /** */
+    private static final Pattern CONSTRUCTOR_EXPRESSION;
+
+    /** */
+    private static final int QUERY_JOIN_ALIAS_GROUP_INDEX = 3;
+
+    /** */
+    private static final int VARIABLE_NAME_GROUP_INDEX = 4;
+
+    /** */
+    private static final Pattern FUNCTION_PATTERN;
+
+    static {
+
+        StringBuilder builder = new StringBuilder();
+        builder.append("(?<=from)"); // from as starting delimiter
+        builder.append("(?:\\s)+"); // at least one space separating
+        builder.append(IDENTIFIER_GROUP); // Entity name, can be qualified (any
+        builder.append("(?:\\sas)*"); // exclude possible "as" keyword
+        builder.append("(?:\\s)+"); // at least one space separating
+        builder.append("(?!(?:where))(\\w+)"); // the actual alias
+
+        ALIAS_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
+
+        builder = new StringBuilder();
+        builder.append("(select\\s+((distinct )?(.+?)?)\\s+)?(from\\s+");
+        builder.append(IDENTIFIER);
+        builder.append("(?:\\s+as)?\\s+)");
+        builder.append(IDENTIFIER_GROUP);
+        builder.append("(.*)");
+
+        COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
+
+        builder = new StringBuilder();
+        builder.append("select");
+        builder.append("\\s+"); // at least one space separating
+        builder.append("(.*\\s+)?"); // anything in between (e.g. distinct) at least one space separating
+        builder.append("new");
+        builder.append("\\s+"); // at least one space separating
+        builder.append(IDENTIFIER);
+        builder.append("\\s*"); // zero to unlimited space separating
+        builder.append("\\(");
+        builder.append(".*");
+        builder.append("\\)");
+
+        CONSTRUCTOR_EXPRESSION = compile(builder.toString(), CASE_INSENSITIVE + DOTALL);
+
+        builder = new StringBuilder();
+        // any function call including parameters within the brackets
+        builder.append("\\w+\\s*\\([\\w\\.,\\s'=]+\\)");
+        // the potential alias
+        builder.append("\\s+[as|AS]+\\s+(([\\w\\.]+))");
+
+        FUNCTION_PATTERN = compile(builder.toString());
+    }
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private QueryUtils() {
+
+    }
+
+    /**
+     * Returns the query string to execute an exists query for the given id attributes.
+     *
+     * @param entityName        the name of the entity to create the query for, must not be {@literal null}.
+     * @param cntQryPlaceHolder the placeholder for the count clause, must not be {@literal null}.
+     * @param idAttrs           the id attributes for the entity, must not be {@literal null}.
+     * @return the exists query string
+     */
+    public static String getExistsQueryString(String entityName,
+        String cntQryPlaceHolder,
+        Iterable<String> idAttrs) {
+
+        String whereClause = Streamable.of(idAttrs).stream() //
+            .map(idAttribute -> String.format(EQUALS_CONDITION_STRING, "x", idAttribute,
+                idAttribute)) //
+            .collect(Collectors.joining(" AND ", " WHERE ", ""));
+
+        return String.format(COUNT_QUERY_STRING, cntQryPlaceHolder, entityName) + whereClause;
+    }
+
+    /**
+     * Returns the query string for the given class name.
+     *
+     * @param template   must not be {@literal null}.
+     * @param entityName must not be {@literal null}.
+     * @return the template with placeholders replaced by the {@literal entityName}. Guaranteed to be not {@literal
+     * null}.
+     */
+    public static String getQueryString(String template, String entityName) {
+
+        Assert.hasText(entityName, "Entity name must not be null or empty!");
+
+        return String.format(template, entityName);
+    }
+
+    /**
+     * Returns the aliases used for {@code left (outer) join}s.
+     *
+     * @param qry a query string to extract the aliases of joins from. Must not be {@literal null}.
+     * @return a {@literal Set} of aliases used in the query. Guaranteed to be not {@literal null}.
+     */
+    static Set<String> getOuterJoinAliases(String qry) {
+
+        Set<String> result = new HashSet<>();
+        Matcher matcher = JOIN_PATTERN.matcher(qry);
+
+        while (matcher.find()) {
+
+            String alias = matcher.group(QUERY_JOIN_ALIAS_GROUP_INDEX);
+            if (StringUtils.hasText(alias))
+                result.add(alias);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the aliases used for aggregate functions like {@code SUM, COUNT, ...}.
+     *
+     * @param qry a {@literal String} containing a query. Must not be {@literal null}.
+     * @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
+     */
+    static Set<String> getFunctionAliases(String qry) {
+
+        Set<String> result = new HashSet<>();
+        Matcher matcher = FUNCTION_PATTERN.matcher(qry);
+
+        while (matcher.find()) {
+
+            String alias = matcher.group(1);
+
+            if (StringUtils.hasText(alias))
+                result.add(alias);
+        }
+
+        return result;
+    }
+
+    /**
+     * Resolves the alias for the entity to be retrieved from the given JPA query.
+     *
+     * @param qry must not be {@literal null}.
+     * @return Might return {@literal null}.
+     * @deprecated use {@link DeclaredQuery#getAlias()} instead.
+     */
+    @Nullable
+    @Deprecated
+    public static String detectAlias(String qry) {
+
+        Matcher matcher = ALIAS_MATCH.matcher(qry);
+
+        return matcher.find() ? matcher.group(2) : null;
+    }
+
+    /**
+     * Creates a count projected query from the given original query.
+     *
+     * @param originalQry must not be {@literal null} or empty.
+     * @return Guaranteed to be not {@literal null}.
+     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
+     */
+    @Deprecated
+    public static String createCountQueryFor(String originalQry) {
+        return createCountQueryFor(originalQry, null);
+    }
+
+    /**
+     * Creates a count projected query from the given original query.
+     *
+     * @param originalQry   must not be {@literal null}.
+     * @param cntProjection may be {@literal null}.
+     * @return a query String to be used a count query for pagination. Guaranteed to be not {@literal null}.
+     * @since 1.6
+     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
+     */
+    @Deprecated
+    public static String createCountQueryFor(String originalQry, @Nullable String cntProjection) {
+
+        Assert.hasText(originalQry, "OriginalQuery must not be null or empty!");
+
+        Matcher matcher = COUNT_MATCH.matcher(originalQry);
+        String countQuery;
+
+        if (cntProjection == null) {
+
+            String variable = matcher.matches() ? matcher.group(VARIABLE_NAME_GROUP_INDEX) : null;
+            boolean useVariable = variable != null && StringUtils.hasText(variable) && !variable.startsWith("new")
+                && !variable.startsWith("count(") && !variable.contains(",");
+
+            String replacement = useVariable ? SIMPLE_COUNT_VALUE : COMPLEX_COUNT_VALUE;
+            countQuery = matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE, replacement));
+        }
+        else
+            countQuery = matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE, cntProjection));
+
+        return countQuery.replaceFirst(ORDER_BY_PART, "");
+    }
+
+    /**
+     * Returns whether the given query contains named parameters.
+     *
+     * @param qry can be {@literal null} or empty.
+     * @return whether the given query contains named parameters.
+     */
+    @Deprecated
+    static boolean hasNamedParameter(@Nullable String qry) {
+        return StringUtils.hasText(qry) && NAMED_PARAMETER.matcher(qry).find();
+    }
+
+    /**
+     * Returns whether the given JPQL query contains a constructor expression.
+     *
+     * @param qry must not be {@literal null} or empty.
+     * @return boolean
+     * @since 1.10
+     */
+    public static boolean hasConstructorExpression(String qry) {
+
+        Assert.hasText(qry, "Query must not be null or empty!");
+
+        return CONSTRUCTOR_EXPRESSION.matcher(qry).find();
+    }
+
+    /**
+     * Returns the projection part of the query, i.e. everything between {@code select} and {@code from}.
+     *
+     * @param qry must not be {@literal null} or empty.
+     * @return projection
+     * @since 1.10.2
+     */
+    public static String getProjection(String qry) {
+
+        Assert.hasText(qry, "Query must not be null or empty!");
+
+        Matcher matcher = PROJECTION_CLAUSE.matcher(qry);
+        String projection = matcher.find() ? matcher.group(1) : "";
+        return projection.trim();
+    }
+
+}
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java
new file mode 100644
index 0000000..bad39b2
--- /dev/null
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java
@@ -0,0 +1,903 @@
+/*
+ * Copyright 2013-2019 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
+ *
+ *      http://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 org.apache.ignite.springdata22.repository.query;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.springframework.data.repository.query.SpelQueryContext;
+import org.springframework.data.repository.query.SpelQueryContext.SpelExtractor;
+
+import org.springframework.data.domain.Range;
+import org.springframework.data.domain.Range.Bound;
+import org.springframework.data.repository.query.parser.Part.Type;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import static java.util.regex.Pattern.CASE_INSENSITIVE;
+import static org.springframework.util.ObjectUtils.nullSafeEquals;
+import static org.springframework.util.ObjectUtils.nullSafeHashCode;
+
+/**
+ * Encapsulation of a JPA query String. Offers access to parameters as bindings. The internal query String is cleaned
+ * from decorated parameters like {@literal %:lastname%} and the matching bindings take care of applying the decorations
+ * in the {@link ParameterBinding#prepare(Object)} method. Note that this class also handles replacing SpEL expressions
+ * with synthetic bind parameters
+ *
+ * @author Oliver Gierke
+ * @author Thomas Darimont
+ * @author Oliver Wehrens
+ * @author Mark Paluch
+ * @author Jens Schauder
+ */
+class StringQuery implements DeclaredQuery {
+
+    private final String query;
+
+    private final List<ParameterBinding> bindings;
+
+    @Nullable
+    private final String alias;
+
+    private final boolean hasConstructorExpression;
+
+    private final boolean containsPageableInSpel;
+
+    private final boolean usesJdbcStyleParameters;
+
+    /**
+     * Creates a new {@link StringQuery} from the given JPQL query.
+     *
+     * @param query must not be {@literal null} or empty.
+     */
+    @SuppressWarnings("deprecation") StringQuery(String query) {
+
+        Assert.hasText(query, "Query must not be null or empty!");
+
+        bindings = new ArrayList<>();
+        containsPageableInSpel = query.contains("#pageable");
+
+        Metadata queryMeta = new Metadata();
+        this.query = ParameterBindingParser.INSTANCE
+            .parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query, bindings,
+                queryMeta);
+
+        usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
+        alias = QueryUtils.detectAlias(query);
+        hasConstructorExpression = QueryUtils.hasConstructorExpression(query);
+    }
+
+    /**
+     * Returns whether we have found some like bindings.
+     */
+    boolean hasParameterBindings() {
+        return !bindings.isEmpty();
+    }
+
+    String getProjection() {
+        return QueryUtils.getProjection(query);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getParameterBindings()
+     */
+    @Override public List<ParameterBinding> getParameterBindings() {
+        return bindings;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#deriveCountQuery(java.lang.String, java.lang
+     * .String)
+     */
+    @SuppressWarnings("deprecation")
+    @Override public DeclaredQuery deriveCountQuery(@Nullable String countQuery,
+        @Nullable String countQueryProjection) {
+
+        return DeclaredQuery
+            .of(countQuery != null ? countQuery : QueryUtils.createCountQueryFor(query, countQueryProjection));
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesJdbcStyleParameters()
+     */
+    @Override public boolean usesJdbcStyleParameters() {
+        return usesJdbcStyleParameters;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getQueryString()
+     */
+    @Override public String getQueryString() {
+        return query;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getAlias()
+     */
+    @Override @Nullable
+    public String getAlias() {
+        return alias;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasConstructorExpression()
+     */
+    @Override public boolean hasConstructorExpression() {
+        return hasConstructorExpression;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#isDefaultProjection()
+     */
+    @Override public boolean isDefaultProjection() {
+        return getProjection().equalsIgnoreCase(alias);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasNamedParameter()
+     */
+    @Override public boolean hasNamedParameter() {
+        return bindings.stream().anyMatch(b -> b.getName() != null);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesPaging()
+     */
+    @Override public boolean usesPaging() {
+        return containsPageableInSpel;
+    }
+
+    /**
+     * A parser that extracts the parameter bindings from a given query string.
+     *
+     * @author Thomas Darimont
+     */
+    enum ParameterBindingParser {
+        INSTANCE;
+        private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
+        public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
+        // .....................................................................^ not followed by a hash or a letter.
+        // .................................................................^ zero or more digits.
+        // .............................................................^ start with a question mark.
+        private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile(POSITIONAL_OR_INDEXED_PARAMETER);
+        private static final Pattern PARAMETER_BINDING_PATTERN;
+        private static final String MESSAGE =
+            "Already found parameter binding with same index / parameter name but differing binding type! "
+                + "Already have: %s, found %s! If you bind a parameter multiple times make sure they use the same "
+                + "binding.";
+        private static final int INDEXED_PARAMETER_GROUP = 4;
+        private static final int NAMED_PARAMETER_GROUP = 6;
+        private static final int COMPARISION_TYPE_GROUP = 1;
+
+        static {
+
+            List<String> keywords = new ArrayList<>();
+
+            for (ParameterBindingType type : ParameterBindingType.values()) {
... 2965 lines suppressed ...


[ignite] 02/02: Stylistic fixes.

Posted by il...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ilyak pushed a commit to branch ignite-13005
in repository https://gitbox.apache.org/repos/asf/ignite.git

commit 0e36155a372190a63d27e0c7a59a6c3831d2ac4f
Author: Ilya Kasnacheev <il...@gmail.com>
AuthorDate: Tue Jun 30 21:03:40 2020 +0300

    Stylistic fixes.
---
 .../springdata20/repository/IgniteRepository.java  |   4 +-
 .../repository/config/DynamicQueryConfig.java      |  75 ++-------
 .../config/IgniteRepositoriesRegistar.java         |   8 +-
 .../IgniteRepositoryConfigurationExtension.java    |  16 +-
 .../springdata20/repository/config/Query.java      |  10 --
 .../repository/query/DeclaredQuery.java            |   5 -
 .../repository/query/EmptyDeclaredQuery.java       |  33 +---
 .../query/ExpressionBasedStringQuery.java          |   1 -
 .../springdata20/repository/query/IgniteQuery.java |  25 +--
 .../repository/query/IgniteQueryGenerator.java     |   5 +-
 .../repository/query/IgniteRepositoryQuery.java    | 176 +++++++-------------
 .../springdata20/repository/query/QueryUtils.java  |  51 +-----
 .../springdata20/repository/query/StringQuery.java | 171 +++++++++-----------
 .../repository/query/spel/SpelEvaluator.java       |  19 +--
 .../repository/query/spel/SpelQueryContext.java    |  52 ++----
 .../repository/support/ConditionFalse.java         |   4 +-
 .../support/IgniteRepositoryFactory.java           |  46 ++----
 .../support/IgniteRepositoryFactoryBean.java       |  12 +-
 .../repository/support/IgniteRepositoryImpl.java   | 101 +++---------
 .../IgniteSpringDataCrudSelfExpressionTest.java    |  47 ++----
 .../springdata/IgniteSpringDataCrudSelfTest.java   |  52 +++---
 .../IgniteSpringDataQueriesSelfTest.java           |  95 ++++-------
 .../springdata/misc/ApplicationConfiguration.java  |   9 +-
 .../ignite/springdata/misc/FullNameProjection.java |   1 -
 .../ignite/springdata/misc/PersonProjection.java   |   2 +-
 .../ignite/springdata/misc/PersonRepository.java   |   2 +-
 .../misc/SampleEvaluationContextExtension.java     |  10 +-
 .../springdata22/repository/IgniteRepository.java  |   4 +-
 .../repository/config/DynamicQueryConfig.java      |  75 ++-------
 .../config/IgniteRepositoriesRegistar.java         |   8 +-
 .../IgniteRepositoryConfigurationExtension.java    |  16 +-
 .../springdata22/repository/config/Query.java      |  11 --
 .../repository/query/DeclaredQuery.java            |   5 -
 .../repository/query/EmptyDeclaredQuery.java       |  33 +---
 .../query/ExpressionBasedStringQuery.java          |   1 -
 .../springdata22/repository/query/IgniteQuery.java |  25 +--
 .../repository/query/IgniteQueryGenerator.java     |   5 +-
 .../repository/query/IgniteRepositoryQuery.java    | 177 +++++++--------------
 .../springdata22/repository/query/QueryUtils.java  |  51 +-----
 .../springdata22/repository/query/StringQuery.java | 172 +++++++++-----------
 .../repository/support/ConditionFalse.java         |   4 +-
 .../support/IgniteRepositoryFactory.java           |  46 ++----
 .../support/IgniteRepositoryFactoryBean.java       |  12 +-
 .../repository/support/IgniteRepositoryImpl.java   | 101 +++---------
 .../IgniteSpringDataCrudSelfExpressionTest.java    |  47 ++----
 .../springdata/IgniteSpringDataCrudSelfTest.java   |  52 +++---
 .../IgniteSpringDataQueriesSelfTest.java           |  95 ++++-------
 .../springdata/misc/ApplicationConfiguration.java  |   9 +-
 .../ignite/springdata/misc/FullNameProjection.java |   1 -
 .../ignite/springdata/misc/PersonProjection.java   |   2 +-
 .../ignite/springdata/misc/PersonRepository.java   |   2 +-
 .../misc/SampleEvaluationContextExtension.java     |  13 +-
 52 files changed, 594 insertions(+), 1405 deletions(-)

diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java
index d311d72..7dee951 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/IgniteRepository.java
@@ -66,7 +66,7 @@ public interface IgniteRepository<V, K extends Serializable> extends CrudReposit
      * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
      * (keys) that are not unique cluster wide.
      *
-     * @param <S>      type of entities.
+     * @param <S>      Type of entities.
      * @param entities Map of key-entities pairs to save.
      * @return Saved entities.
      */
@@ -92,7 +92,7 @@ public interface IgniteRepository<V, K extends Serializable> extends CrudReposit
      * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
      * (keys) that are not unique cluster wide.
      *
-     * @param <S>       type of entities.
+     * @param <S>       Type of entities.
      * @param entities  Map of key-entities pairs to save.
      * @param expiryPlc ExpiryPolicy to apply, if not null.
      * @return Saved entities.
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java
index 82bc02c..ed422a9 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/DynamicQueryConfig.java
@@ -31,64 +31,37 @@ package org.apache.ignite.springdata20.repository.config;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public class DynamicQueryConfig {
-    /**
-     * Value.
-     */
+    /** */
     private String value = "";
 
-    /**
-     * Text query.
-     */
+    /** */
     private boolean textQuery;
 
-    /**
-     * Force fields query.
-     */
+    /** */
     private boolean forceFieldsQry;
 
-    /**
-     * Collocated.
-     */
+    /** */
     private boolean collocated;
 
-    /**
-     * Timeout.
-     */
+    /** */
     private int timeout;
 
-    /**
-     * Enforce join order.
-     */
+    /** */
     private boolean enforceJoinOrder;
 
-    /**
-     * Distributed joins.
-     */
+    /** */
     private boolean distributedJoins;
 
-    /**
-     * Replicated only.
-     */
-    private boolean replicatedOnly;
-
-    /**
-     * Lazy.
-     */
+    /** */
     private boolean lazy;
 
-    /**
-     * Local.
-     */
+    /** */
     private boolean local;
 
-    /**
-     * Parts.
-     */
+    /** */
     private int[] parts;
 
-    /**
-     * Limit.
-     */
+    /** */
     private int limit;
 
     /**
@@ -105,7 +78,6 @@ public class DynamicQueryConfig {
             config.timeout = queryConfiguration.timeout();
             config.enforceJoinOrder = queryConfiguration.enforceJoinOrder();
             config.distributedJoins = queryConfiguration.distributedJoins();
-            config.replicatedOnly = queryConfiguration.replicatedOnly();
             config.lazy = queryConfiguration.lazy();
             config.parts = queryConfiguration.parts();
             config.local = queryConfiguration.local();
@@ -201,19 +173,6 @@ public class DynamicQueryConfig {
     }
 
     /**
-     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
-     * <p>
-     * Only applicable to SqlFieldsQuery and SqlQuery
-     *
-     * @return the boolean
-     * @deprecated No longer used as of Apache Ignite 2.8.
-     */
-    @Deprecated
-    public boolean replicatedOnly() {
-        return replicatedOnly;
-    }
-
-    /**
      * Sets lazy query execution flag.
      * <p>
      * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
@@ -344,17 +303,6 @@ public class DynamicQueryConfig {
     }
 
     /**
-     * Sets replicated only.
-     *
-     * @param replicatedOnly the replicated only
-     * @return this for chaining
-     */
-    public DynamicQueryConfig setReplicatedOnly(boolean replicatedOnly) {
-        this.replicatedOnly = replicatedOnly;
-        return this;
-    }
-
-    /**
      * Sets lazy.
      *
      * @param lazy the lazy
@@ -397,5 +345,4 @@ public class DynamicQueryConfig {
         this.limit = limit;
         return this;
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java
index 546eb2f..83ff7ff 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoriesRegistar.java
@@ -24,16 +24,12 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryBeanDefinitionRegistrarSupport}.
  */
 public class IgniteRepositoriesRegistar extends RepositoryBeanDefinitionRegistrarSupport {
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected Class<? extends Annotation> getAnnotation() {
         return EnableIgniteRepositories.class;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected RepositoryConfigurationExtension getExtension() {
         return new IgniteRepositoryConfigurationExtension();
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
index 9cd36ec..354e35b 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -27,30 +27,22 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getModuleName() {
         return "Apache Ignite";
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected String getModulePrefix() {
         return "ignite";
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getRepositoryFactoryBeanClassName() {
         return IgniteRepositoryFactoryBean.class.getName();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
         return Collections.singleton(IgniteRepository.class);
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java
index 394ed43..7b44d19 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/config/Query.java
@@ -89,16 +89,6 @@ public @interface Query {
     boolean distributedJoins() default false;
 
     /**
-     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
-     * <p>
-     * Only applicable to SqlFieldsQuery and SqlQuery
-     *
-     * @deprecated No longer used as of Apache Ignite 2.8.
-     */
-    @Deprecated
-    boolean replicatedOnly() default false;
-
-    /**
      * Sets lazy query execution flag.
      * <p>
      * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java
index 9edf321..42450ba 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/DeclaredQuery.java
@@ -23,7 +23,6 @@ import org.springframework.util.StringUtils;
  * A wrapper for a String representation of a query offering information about the query.
  *
  * @author Jens Schauder
- * @since 2.0.3
  */
 interface DeclaredQuery {
     /**
@@ -56,8 +55,6 @@ interface DeclaredQuery {
 
     /**
      * Returns whether the query is using a constructor expression.
-     *
-     * @since 1.10
      */
     public boolean hasConstructorExpression();
 
@@ -84,7 +81,6 @@ interface DeclaredQuery {
 
     /**
      * @return whether paging is implemented in the query itself, e.g. using SpEL expressions.
-     * @since 2.0.6
      */
     public default boolean usesPaging() {
         return false;
@@ -95,7 +91,6 @@ interface DeclaredQuery {
      * name.
      *
      * @return Whether the query uses JDBC style parameters.
-     * @since 2.0.6
      */
     public boolean usesJdbcStyleParameters();
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java
index 243c36e..85eeaf6 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/EmptyDeclaredQuery.java
@@ -24,7 +24,6 @@ import org.springframework.util.Assert;
  * NULL-Object pattern implementation for {@link DeclaredQuery}.
  *
  * @author Jens Schauder
- * @since 2.0.3
  */
 class EmptyDeclaredQuery implements DeclaredQuery {
     /**
@@ -32,59 +31,43 @@ class EmptyDeclaredQuery implements DeclaredQuery {
      */
     static final DeclaredQuery EMPTY_QUERY = new EmptyDeclaredQuery();
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean hasNamedParameter() {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getQueryString() {
         return "";
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getAlias() {
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean hasConstructorExpression() {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean isDefaultProjection() {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public List<StringQuery.ParameterBinding> getParameterBindings() {
         return Collections.emptyList();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public DeclaredQuery deriveCountQuery(@Nullable String cntQry, @Nullable String cntQryProjection) {
         Assert.hasText(cntQry, "CountQuery must not be empty!");
         return DeclaredQuery.of(cntQry);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean usesJdbcStyleParameters() {
         return false;
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java
index 3791985..b7559a5 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/ExpressionBasedStringQuery.java
@@ -150,5 +150,4 @@ class ExpressionBasedStringQuery extends StringQuery {
     private static boolean containsExpression(String qry) {
         return qry.contains(ENTITY_NAME_VARIABLE_EXPRESSION);
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java
index 7e75bc2..44215a0 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQuery.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.springdata20.repository.query;
 
-import java.util.StringJoiner;
+import org.apache.ignite.internal.util.typedef.internal.S;
 
 /**
  * Ignite query helper class. For internal use only.
@@ -26,24 +26,15 @@ import java.util.StringJoiner;
  * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteQuery {
-
-    /**
-     *
-     */
+    /** */
     enum Option {
-        /**
-         * Query will be used with Sort object.
-         */
+        /** Query will be used with Sort object. */
         SORTING,
 
-        /**
-         * Query will be used with Pageable object.
-         */
+        /** Query will be used with Pageable object. */
         PAGINATION,
 
-        /**
-         * No advanced option.
-         */
+        /** No advanced option. */
         NONE
     }
 
@@ -136,10 +127,8 @@ public class IgniteQuery {
         return option;
     }
 
+    /** */
     @Override public String toString() {
-        return new StringJoiner(", ", IgniteQuery.class.getSimpleName() + "[", "]").add("qrySql='" + qrySql + "'")
-            .add("isFieldQuery=" + isFieldQuery).add("isTextQuery=" + isTextQuery)
-            .add("isAutogenerated=" + isAutogenerated).add("option=" + option).toString();
+        return S.toString(IgniteQuery.class, this);
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java
index f8eb64c..a5b13b5 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteQueryGenerator.java
@@ -29,8 +29,9 @@ import org.springframework.data.repository.query.parser.PartTree;
  * Ignite query generator for Spring Data framework.
  */
 public class IgniteQueryGenerator {
-
+    /** */
     private IgniteQueryGenerator() {
+        // No-op.
     }
 
     /**
@@ -38,7 +39,6 @@ public class IgniteQueryGenerator {
      * @param metadata Metadata.
      * @return Generated ignite query.
      */
-    @NotNull
     public static IgniteQuery generateSql(Method mtd, RepositoryMetadata metadata) {
         PartTree parts = new PartTree(mtd.getName(), metadata.getDomainType());
 
@@ -253,5 +253,4 @@ public class IgniteQueryGenerator {
 
         sql.append(")");
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java
index 06ed98f..c01acf0 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/IgniteRepositoryQuery.java
@@ -155,166 +155,105 @@ import static org.apache.ignite.springdata20.repository.support.IgniteRepository
  * </pre>
  * </li>
  * </ol>
- * <p>
- * Visit <a href="https://docs.hawkore.com/private/apache-ignite-advanced-indexing">Apache Ignite advanced Indexing
- * Documentation site</a> for more info about Advanced Lucene Index and Lucene Query Builder.
  *
  * @author Apache Ignite Team
  * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 @SuppressWarnings("unchecked")
 public class IgniteRepositoryQuery implements RepositoryQuery {
-
+    /** */
     private static final TreeMap<String, Class<?>> binaryFieldClass = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     /**
      * Defines the way how to process query result
      */
     private enum ReturnStrategy {
-        /**
-         * Need to return only one value.
-         */
+        /** Need to return only one value. */
         ONE_VALUE,
 
-        /**
-         * Need to return one cache entry
-         */
+        /** Need to return one cache entry */
         CACHE_ENTRY,
 
-        /**
-         * Need to return list of cache entries
-         */
+        /** Need to return list of cache entries */
         LIST_OF_CACHE_ENTRIES,
 
-        /**
-         * Need to return list of values
-         */
+        /** Need to return list of values */
         LIST_OF_VALUES,
 
-        /**
-         * Need to return list of lists
-         */
+        /** Need to return list of lists */
         LIST_OF_LISTS,
 
-        /**
-         * Need to return slice
-         */
+        /** Need to return slice */
         SLICE_OF_VALUES,
 
-        /**
-         * Slice of cache entries.
-         */
+        /** Slice of cache entries */
         SLICE_OF_CACHE_ENTRIES,
 
-        /**
-         * Slice of lists.
-         */
+        /** Slice of lists */
         SLICE_OF_LISTS,
 
-        /**
-         * Need to return Page of values
-         */
+        /** Need to return Page of values */
         PAGE_OF_VALUES,
 
-        /**
-         * Need to return stream of values
-         */
+        /** Need to return stream of values */
         STREAM_OF_VALUES,
     }
 
-    /**
-     * Type.
-     */
+    /** */
     private final Class<?> type;
 
-    /**
-     * Sql.
-     */
+    /** */
     private final IgniteQuery staticQuery;
 
-    /**
-     * Cache.
-     */
+    /** */
     private final IgniteCache cache;
 
-    /**
-     * Ignite instance
-     */
+    /** */
     private final Ignite ignite;
 
-    /**
-     * required by qryStr field query type for binary manipulation
-     */
+    /** Required by qryStr field query type for binary manipulation */
     private IgniteBinaryImpl igniteBinary;
 
-    /**
-     * Ignite bin type.
-     */
+    /** */
     private BinaryType igniteBinType;
 
-    /**
-     * Method.
-     */
+    /** */
     private final Method mtd;
 
-    /**
-     * Metadata.
-     */
+    /** */
     private final RepositoryMetadata metadata;
 
-    /**
-     * Factory.
-     */
+    /** */
     private final ProjectionFactory factory;
 
-    /**
-     * Return strategy.
-     */
+    /** */
     private final ReturnStrategy staticReturnStgy;
 
-    /**
-     * Detect if returned data from method is projected
-     */
+    /** Detect if returned data from method is projected */
     private final boolean hasProjection;
 
-    /**
-     * Whether projection is dynamic (provided as method parameter)
-     */
+    /** Whether projection is dynamic (provided as method parameter) */
     private final boolean hasDynamicProjection;
 
-    /**
-     * Dynamic projection parameter index.
-     */
+    /** Dynamic projection parameter index */
     private final int dynamicProjectionIndex;
 
-    /**
-     * Dynamic query configuration.
-     */
+    /** Dynamic query configuration */
     private final int dynamicQueryConfigurationIndex;
 
-    /**
-     * the return query method
-     */
+    /** The return query method */
     private final QueryMethod qMethod;
 
-    /**
-     * the return domain class of QueryMethod
-     */
+    /** The return domain class of QueryMethod */
     private final Class<?> returnedDomainClass;
 
-    /**
-     * Expression parser.
-     */
+    /** */
     private final SpelExpressionParser expressionParser;
 
-    /**
-     * could provide ExtensionAwareQueryMethodEvaluationContextProvider
-     */
+    /** Could provide ExtensionAwareQueryMethodEvaluationContextProvider */
     private final EvaluationContextProvider queryMethodEvaluationContextProvider;
 
-    /**
-     * Static query configuration.
-     */
+    /** Static query configuration. */
     private final DynamicQueryConfig staticQueryConfiguration;
 
     /**
@@ -385,7 +324,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      * @return the object
      */
     @Override public Object execute(Object[] values) {
-
         Object[] parameters = values;
 
         // config via Query annotation (dynamicQuery = false)
@@ -419,9 +357,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         return transformQueryCursor(qry, returnStgy, parameters, qryCursor);
     }
 
-    /**
-     * {@inheritDoc} @return the query method
-     */
+    /** {@inheritDoc} */
     @Override public QueryMethod getQueryMethod() {
         return new QueryMethod(mtd, metadata, factory);
     }
@@ -433,28 +369,35 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         int index = -1;
         while (it.hasNext()) {
             T parameter = it.next();
+
             if (DynamicQueryConfig.class.isAssignableFrom(parameter.getType())) {
                 if (found) {
                     throw new IllegalStateException("Invalid '" + method.getName() + "' repository method signature. "
                         + "Only ONE DynamicQueryConfig parameter is allowed");
                 }
+
                 found = true;
                 index = i;
             }
+
             i++;
         }
         return index;
     }
 
+    /** */
     private synchronized IgniteBinaryImpl binary() {
         if (igniteBinary == null)
             igniteBinary = (IgniteBinaryImpl)ignite.binary();
+
         return igniteBinary;
     }
 
+    /** */
     private synchronized BinaryType binType() {
         if (igniteBinType == null)
             igniteBinType = binary().type(type);
+
         return igniteBinType;
     }
 
@@ -500,7 +443,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      * @return if {@code mtd} return type is assignable from {@code cls}
      */
     private boolean hasAssignableGenericReturnTypeFrom(Class<?> cls, Method mtd) {
-
         Type genericReturnType = mtd.getGenericReturnType();
 
         if (!(genericReturnType instanceof ParameterizedType))
@@ -529,7 +471,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     }
 
     /**
-     * when select fields by query H2 returns Timestamp for types java.util.Date and java.qryStr.Timestamp
+     * When select fields by query H2 returns Timestamp for types java.util.Date and java.qryStr.Timestamp
      *
      * @see org.apache.ignite.internal.processors.query.h2.H2DatabaseType map.put(Timestamp.class, TIMESTAMP)
      * map.put(java.util.Date.class, TIMESTAMP) map.put(java.qryStr.Date.class, DATE)
@@ -537,6 +479,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private static <T> T fixExpectedType(final Object object, final Class<T> expected) {
         if (expected != null && object instanceof java.sql.Timestamp && expected.equals(java.util.Date.class))
             return (T)new java.util.Date(((java.sql.Timestamp)object).getTime());
+
         return (T)object;
     }
 
@@ -546,11 +489,13 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private IgniteQuery getQuery(@Nullable DynamicQueryConfig cfg) {
         if (staticQuery != null)
             return staticQuery;
+
         if (cfg != null && (StringUtils.hasText(cfg.value()) || cfg.textQuery())) {
             return new IgniteQuery(cfg.value(),
                 !cfg.textQuery() && (isFieldQuery(cfg.value()) || cfg.forceFieldsQuery()), cfg.textQuery(),
                 false, IgniteQueryGenerator.getOptions(mtd));
         }
+
         throw new IllegalStateException("Unable to obtain a valid query. When passing dynamicQuery = true via org"
             + ".apache.ignite.springdata.repository.config.Query annotation, you must"
             + " provide a non null method parameter of type DynamicQueryConfig with a "
@@ -563,8 +508,10 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private ReturnStrategy getReturnStgy(IgniteQuery qry) {
         if (staticReturnStgy != null)
             return staticReturnStgy;
+
         if (qry != null)
             return calcReturnType(mtd, qry.isFieldQuery());
+
         throw new IllegalStateException("Unable to obtain a valid return strategy. When passing dynamicQuery = true "
             + "via org.apache.ignite.springdata.repository.config.Query annotation, "
             + "you must provide a non null method parameter of type "
@@ -600,7 +547,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         ReturnStrategy returnStgy,
         Object[] prmtrs,
         QueryCursor qryCursor) {
-
         final Class<?> returnClass;
 
         if (hasProjection) {
@@ -726,7 +672,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private Object[] extractBindableValues(Object[] values,
         Parameters<?, ?> queryMethodParams,
         List<ParameterBinding> queryBindings) {
-
         // no binding params then exit
         if (queryBindings.isEmpty())
             return values;
@@ -785,7 +730,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      */
     @NotNull
     private Query prepareQuery(IgniteQuery qry, DynamicQueryConfig config, ReturnStrategy returnStgy, Object[] values) {
-
         Object[] parameters = values;
 
         String queryString = qry.qryStr();
@@ -795,7 +739,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         checkRequiredPageable(returnStgy, values);
 
         if (!qry.isTextQuery()) {
-
             if (!qry.isAutogenerated()) {
                 StringQuery squery = new ExpressionBasedStringQuery(queryString, metadata, expressionParser);
                 queryString = squery.getQueryString();
@@ -839,7 +782,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
                 if (config.parts() != null && config.parts().length > 0)
                     sqlFieldsQry.setPartitions(config.parts());
 
-                sqlFieldsQry.setReplicatedOnly(config.replicatedOnly());
                 sqlFieldsQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
 
                 query = sqlFieldsQry;
@@ -850,16 +792,16 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
 
                 sqlQry.setDistributedJoins(config.distributedJoins());
                 sqlQry.setLocal(config.local());
+
                 if (config.parts() != null && config.parts().length > 0)
                     sqlQry.setPartitions(config.parts());
-                sqlQry.setReplicatedOnly(config.replicatedOnly());
+
                 sqlQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
 
                 query = sqlQry;
             }
         }
         else {
-
             int pageSize = -1;
 
             switch (qry.options()) {
@@ -898,6 +840,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         return query;
     }
 
+    /** */
     private static Map<String, Object> rowToMap(final List<?> row, final List<GridQueryFieldMetadata> meta) {
         // use treemap with case insensitive property name
         final TreeMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -911,7 +854,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         return map;
     }
 
-    /*
+    /**
      * convert row ( with list of field values) into domain entity
      */
     private <V> V rowToEntity(final IgniteBinaryImpl binary,
@@ -952,7 +895,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         final BinaryType binType,
         final GridQueryFieldMetadata fieldMeta) {
         try {
-
             final String fieldId = fieldMeta.schemaName() + "." + fieldMeta.typeName() + "." + fieldMeta.fieldName();
 
             if (binaryFieldClass.containsKey(fieldId))
@@ -1037,7 +979,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      * @param <V> transformed output type
      */
     public static class QueryCursorWrapper<T, V> extends AbstractCollection<V> implements QueryCursor<V> {
-
         /**
          * Delegate query cursor.
          */
@@ -1059,14 +1000,12 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
             this.transformer = transformer;
         }
 
-        /**
-         * {@inheritDoc} @return the iterator
-         */
+        /** {@inheritDoc} */
         @Override public Iterator<V> iterator() {
-
             final Iterator<T> it = delegate.iterator();
 
             return new Iterator<V>() {
+                /** */
                 @Override public boolean hasNext() {
                     if (!it.hasNext()) {
                         U.closeQuiet(delegate);
@@ -1075,6 +1014,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
                     return true;
                 }
 
+                /** */
                 @Override public V next() {
                     final V r = transformer.apply(it.next());
                     if (r != null)
@@ -1084,16 +1024,12 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
             };
         }
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         @Override public void close() {
             U.closeQuiet(delegate);
         }
 
-        /**
-         * {@inheritDoc} @return the all
-         */
+        /** {@inheritDoc} */
         @Override public List<V> getAll() {
             final List<V> data = new ArrayList<>();
             delegate.forEach(i -> data.add(transformer.apply(i)));
@@ -1101,13 +1037,9 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
             return data;
         }
 
-        /**
-         * {@inheritDoc} @return the int
-         */
+        /** {@inheritDoc} */
         @Override public int size() {
             return 0;
         }
-
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java
index e31c0d0..2f74e44 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/QueryUtils.java
@@ -118,7 +118,6 @@ public abstract class QueryUtils {
     private static final Pattern FUNCTION_PATTERN;
 
     static {
-
         StringBuilder builder = new StringBuilder();
         builder.append("(?<=from)"); // from as starting delimiter
         builder.append("(?:\\s)+"); // at least one space separating
@@ -165,7 +164,7 @@ public abstract class QueryUtils {
      * Private constructor to prevent instantiation.
      */
     private QueryUtils() {
-
+        // No-op.
     }
 
     /**
@@ -179,7 +178,6 @@ public abstract class QueryUtils {
     public static String getExistsQueryString(String entityName,
         String cntQryPlaceHolder,
         Iterable<String> idAttrs) {
-
         String whereClause = Streamable.of(idAttrs).stream() //
             .map(idAttribute -> String.format(EQUALS_CONDITION_STRING, "x", idAttribute,
                 idAttribute)) //
@@ -194,10 +192,9 @@ public abstract class QueryUtils {
      * @param template   must not be {@literal null}.
      * @param entityName must not be {@literal null}.
      * @return the template with placeholders replaced by the {@literal entityName}. Guaranteed to be not {@literal
-     * null}.
+     *     null}.
      */
     public static String getQueryString(String template, String entityName) {
-
         Assert.hasText(entityName, "Entity name must not be null or empty!");
 
         return String.format(template, entityName);
@@ -210,12 +207,10 @@ public abstract class QueryUtils {
      * @return a {@literal Set} of aliases used in the query. Guaranteed to be not {@literal null}.
      */
     static Set<String> getOuterJoinAliases(String qry) {
-
         Set<String> result = new HashSet<>();
         Matcher matcher = JOIN_PATTERN.matcher(qry);
 
         while (matcher.find()) {
-
             String alias = matcher.group(QUERY_JOIN_ALIAS_GROUP_INDEX);
             if (StringUtils.hasText(alias))
                 result.add(alias);
@@ -231,12 +226,10 @@ public abstract class QueryUtils {
      * @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
      */
     static Set<String> getFunctionAliases(String qry) {
-
         Set<String> result = new HashSet<>();
         Matcher matcher = FUNCTION_PATTERN.matcher(qry);
 
         while (matcher.find()) {
-
             String alias = matcher.group(1);
 
             if (StringUtils.hasText(alias))
@@ -251,12 +244,9 @@ public abstract class QueryUtils {
      *
      * @param qry must not be {@literal null}.
      * @return Might return {@literal null}.
-     * @deprecated use {@link DeclaredQuery#getAlias()} instead.
      */
     @Nullable
-    @Deprecated
-    public static String detectAlias(String qry) {
-
+    static String detectAlias(String qry) {
         Matcher matcher = ALIAS_MATCH.matcher(qry);
 
         return matcher.find() ? matcher.group(2) : null;
@@ -265,34 +255,17 @@ public abstract class QueryUtils {
     /**
      * Creates a count projected query from the given original query.
      *
-     * @param originalQry must not be {@literal null} or empty.
-     * @return Guaranteed to be not {@literal null}.
-     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
-     */
-    @Deprecated
-    public static String createCountQueryFor(String originalQry) {
-        return createCountQueryFor(originalQry, null);
-    }
-
-    /**
-     * Creates a count projected query from the given original query.
-     *
      * @param originalQry   must not be {@literal null}.
      * @param cntProjection may be {@literal null}.
      * @return a query String to be used a count query for pagination. Guaranteed to be not {@literal null}.
-     * @since 1.6
-     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
      */
-    @Deprecated
-    public static String createCountQueryFor(String originalQry, @Nullable String cntProjection) {
-
+    static String createCountQueryFor(String originalQry, @Nullable String cntProjection) {
         Assert.hasText(originalQry, "OriginalQuery must not be null or empty!");
 
         Matcher matcher = COUNT_MATCH.matcher(originalQry);
         String countQuery;
 
         if (cntProjection == null) {
-
             String variable = matcher.matches() ? matcher.group(VARIABLE_NAME_GROUP_INDEX) : null;
             boolean useVariable = variable != null && StringUtils.hasText(variable) && !variable.startsWith("new")
                 && !variable.startsWith("count(") && !variable.contains(",");
@@ -307,25 +280,12 @@ public abstract class QueryUtils {
     }
 
     /**
-     * Returns whether the given query contains named parameters.
-     *
-     * @param qry can be {@literal null} or empty.
-     * @return whether the given query contains named parameters.
-     */
-    @Deprecated
-    static boolean hasNamedParameter(@Nullable String qry) {
-        return StringUtils.hasText(qry) && NAMED_PARAMETER.matcher(qry).find();
-    }
-
-    /**
      * Returns whether the given JPQL query contains a constructor expression.
      *
      * @param qry must not be {@literal null} or empty.
      * @return boolean
-     * @since 1.10
      */
     public static boolean hasConstructorExpression(String qry) {
-
         Assert.hasText(qry, "Query must not be null or empty!");
 
         return CONSTRUCTOR_EXPRESSION.matcher(qry).find();
@@ -336,15 +296,12 @@ public abstract class QueryUtils {
      *
      * @param qry must not be {@literal null} or empty.
      * @return projection
-     * @since 1.10.2
      */
     public static String getProjection(String qry) {
-
         Assert.hasText(qry, "Query must not be null or empty!");
 
         Matcher matcher = PROJECTION_CLAUSE.matcher(qry);
         String projection = matcher.find() ? matcher.group(1) : "";
         return projection.trim();
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java
index ca056c5..c6e2572 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/StringQuery.java
@@ -50,18 +50,23 @@ import static org.springframework.util.ObjectUtils.nullSafeHashCode;
  * @author Jens Schauder
  */
 class StringQuery implements DeclaredQuery {
-
+    /** */
     private final String query;
 
+    /** */
     private final List<ParameterBinding> bindings;
 
+    /** */
     @Nullable
     private final String alias;
 
+    /** */
     private final boolean hasConstructorExpression;
 
+    /** */
     private final boolean containsPageableInSpel;
 
+    /** */
     private final boolean usesJdbcStyleParameters;
 
     /**
@@ -69,8 +74,7 @@ class StringQuery implements DeclaredQuery {
      *
      * @param query must not be {@literal null} or empty.
      */
-    @SuppressWarnings("deprecation") StringQuery(String query) {
-
+    StringQuery(String query) {
         Assert.hasText(query, "Query must not be null or empty!");
 
         bindings = new ArrayList<>();
@@ -93,84 +97,64 @@ class StringQuery implements DeclaredQuery {
         return !bindings.isEmpty();
     }
 
+    /** */
     String getProjection() {
         return QueryUtils.getProjection(query);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getParameterBindings()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#getParameterBindings()
+    /** {@inheritDoc} */
     @Override public List<ParameterBinding> getParameterBindings() {
         return bindings;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#deriveCountQuery(java.lang.String, java.lang
-     * .String)
-     */
-    @SuppressWarnings("deprecation")
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#deriveCountQuery(java.lang.String, java.lang
+    /** {@inheritDoc} */
     @Override public DeclaredQuery deriveCountQuery(@Nullable String countQuery,
         @Nullable String countQueryProjection) {
-
         return DeclaredQuery
             .of(countQuery != null ? countQuery : QueryUtils.createCountQueryFor(query, countQueryProjection));
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesJdbcStyleParameters()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#usesJdbcStyleParameters()
+    /** */
     @Override public boolean usesJdbcStyleParameters() {
         return usesJdbcStyleParameters;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getQueryString()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#getQueryString()
+    /** {@inheritDoc} */
     @Override public String getQueryString() {
         return query;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getAlias()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#getAlias()
+    /** {@inheritDoc} */
     @Override @Nullable
     public String getAlias() {
         return alias;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasConstructorExpression()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#hasConstructorExpression()
+    /** {@inheritDoc} */
     @Override public boolean hasConstructorExpression() {
         return hasConstructorExpression;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#isDefaultProjection()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#isDefaultProjection()
+    /** {@inheritDoc} */
     @Override public boolean isDefaultProjection() {
         return getProjection().equalsIgnoreCase(alias);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasNamedParameter()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#hasNamedParameter()
+    /** {@inheritDoc} */
     @Override public boolean hasNamedParameter() {
         return bindings.stream().anyMatch(b -> b.getName() != null);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesPaging()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#usesPaging()
+    /** {@inheritDoc} */
     @Override public boolean usesPaging() {
         return containsPageableInSpel;
     }
@@ -181,24 +165,40 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     enum ParameterBindingParser {
+        /** */
         INSTANCE;
+
+        /** */
         private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
+
+        /** */
         public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
         // .....................................................................^ not followed by a hash or a letter.
         // .................................................................^ zero or more digits.
         // .............................................................^ start with a question mark.
+
+        /** */
         private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile(POSITIONAL_OR_INDEXED_PARAMETER);
+
+        /** */
         private static final Pattern PARAMETER_BINDING_PATTERN;
+
+        /** */
         private static final String MESSAGE =
             "Already found parameter binding with same index / parameter name but differing binding type! "
                 + "Already have: %s, found %s! If you bind a parameter multiple times make sure they use the same "
                 + "binding.";
+
+        /** */
         private static final int INDEXED_PARAMETER_GROUP = 4;
+
+        /** */
         private static final int NAMED_PARAMETER_GROUP = 6;
+
+        /** */
         private static final int COMPARISION_TYPE_GROUP = 1;
 
         static {
-
             List<String> keywords = new ArrayList<>();
 
             for (ParameterBindingType type : ParameterBindingType.values()) {
@@ -233,7 +233,6 @@ class StringQuery implements DeclaredQuery {
         private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String query,
             List<ParameterBinding> bindings,
             Metadata queryMeta) {
-
             int greatestParamIdx = tryFindGreatestParameterIndexIn(query);
             boolean parametersShouldBeAccessedByIdx = greatestParamIdx != -1;
 
@@ -255,8 +254,8 @@ class StringQuery implements DeclaredQuery {
             int expressionParamIdx = parametersShouldBeAccessedByIdx ? greatestParamIdx : 0;
 
             boolean usesJpaStyleParameters = false;
-            while (matcher.find()) {
 
+            while (matcher.find()) {
                 if (quotedAreas.isQuoted(matcher.start()))
                     continue;
 
@@ -274,7 +273,6 @@ class StringQuery implements DeclaredQuery {
 
                 expressionParamIdx++;
                 if (paramIdxStr != null && paramIdxStr.isEmpty()) {
-
                     queryMeta.usesJdbcStyleParameters = true;
                     paramIdx = expressionParamIdx;
                 }
@@ -295,9 +293,7 @@ class StringQuery implements DeclaredQuery {
                 }
 
                 switch (ParameterBindingType.of(typeSrc)) {
-
                     case LIKE:
-
                         Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2));
                         replacement = matcher.group(3);
 
@@ -312,7 +308,6 @@ class StringQuery implements DeclaredQuery {
                         break;
 
                     case IN:
-
                         if (paramIdx != null)
                             checkAndRegister(new InParameterBinding(paramIdx, expression), bindings);
                         else
@@ -334,6 +329,7 @@ class StringQuery implements DeclaredQuery {
             return resultingQry;
         }
 
+        /** */
         private static SpelExtractor createSpelExtractor(String queryWithSpel,
             boolean parametersShouldBeAccessedByIndex,
             int greatestParameterIndex) {
@@ -359,8 +355,8 @@ class StringQuery implements DeclaredQuery {
             return SpelQueryContext.of(indexToParameterName, parameterNameToReplacement).parse(queryWithSpel);
         }
 
+        /** */
         private static String replaceFirst(String text, String substring, String replacement) {
-
             int index = text.indexOf(substring);
             if (index < 0)
                 return text;
@@ -368,16 +364,16 @@ class StringQuery implements DeclaredQuery {
             return text.substring(0, index) + replacement + text.substring(index + substring.length());
         }
 
+        /** */
         @Nullable
         private static Integer getParameterIndex(@Nullable String parameterIndexString) {
-
             if (parameterIndexString == null || parameterIndexString.isEmpty())
                 return null;
             return Integer.valueOf(parameterIndexString);
         }
 
+        /** */
         private static int tryFindGreatestParameterIndexIn(String query) {
-
             Matcher parameterIndexMatcher = PARAMETER_BINDING_BY_INDEX.matcher(query);
 
             int greatestParameterIndex = -1;
@@ -392,6 +388,7 @@ class StringQuery implements DeclaredQuery {
             return greatestParameterIndex;
         }
 
+        /** */
         private static void checkAndRegister(ParameterBinding binding, List<ParameterBinding> bindings) {
 
             bindings.stream() //
@@ -411,12 +408,20 @@ class StringQuery implements DeclaredQuery {
         private enum ParameterBindingType {
             // Trailing whitespace is intentional to reflect that the keywords must be used with at least one whitespace
             // character, while = does not.
+            /** */
             LIKE("like "),
+
+            /** */
             IN("in "),
+
+            /** */
             AS_IS(null);
-            private final @Nullable
-            String keyword;
 
+            /** */
+            @Nullable
+            private final String keyword;
+
+            /** */
             ParameterBindingType(@Nullable String keyword) {
                 this.keyword = keyword;
             }
@@ -437,7 +442,6 @@ class StringQuery implements DeclaredQuery {
              * #AS_IS} in case no other {@link ParameterBindingType} could be found.
              */
             static ParameterBindingType of(String typeSource) {
-
                 if (!StringUtils.hasText(typeSource))
                     return AS_IS;
 
@@ -457,12 +461,15 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     static class ParameterBinding {
+        /** */
         @Nullable
         private final String name;
 
+        /** */
         @Nullable
         private final String expression;
 
+        /** */
         @Nullable
         private final Integer position;
 
@@ -523,7 +530,6 @@ class StringQuery implements DeclaredQuery {
         /**
          * @return the name
          * @throws IllegalStateException if the name is not available.
-         * @since 2.0
          */
         String getRequiredName() throws IllegalStateException {
 
@@ -546,7 +552,6 @@ class StringQuery implements DeclaredQuery {
         /**
          * @return the position
          * @throws IllegalStateException if the position is not available.
-         * @since 2.0
          */
         int getRequiredPosition() throws IllegalStateException {
 
@@ -565,10 +570,7 @@ class StringQuery implements DeclaredQuery {
             return expression != null;
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#hashCode()
-         */
+        /** */
         @Override public int hashCode() {
 
             int result = 17;
@@ -580,10 +582,7 @@ class StringQuery implements DeclaredQuery {
             return result;
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
+        /** */
         @Override public boolean equals(Object obj) {
 
             if (!(obj instanceof ParameterBinding))
@@ -595,10 +594,7 @@ class StringQuery implements DeclaredQuery {
                 && nullSafeEquals(expression, that.expression);
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#toString()
-         */
+        /** */
         @Override public String toString() {
             return String.format("ParameterBinding [name: %s, position: %d, expression: %s]", getName(), getPosition(),
                 getExpression());
@@ -612,11 +608,11 @@ class StringQuery implements DeclaredQuery {
             return valueToBind;
         }
 
+        /** */
         @Nullable
         public String getExpression() {
             return expression;
         }
-
     }
 
     /**
@@ -626,7 +622,6 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     static class InParameterBinding extends ParameterBinding {
-
         /**
          * Creates a new {@link InParameterBinding} for the parameter with the given name.
          */
@@ -646,7 +641,6 @@ class StringQuery implements DeclaredQuery {
          * @see org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding#prepare(java.lang.Object)
          */
         @Override public Object prepare(@Nullable Object value) {
-
             if (!ObjectUtils.isArray(value))
                 return value;
 
@@ -669,10 +663,11 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     static class LikeParameterBinding extends ParameterBinding {
-
+        /** */
         private static final List<Type> SUPPORTED_TYPES = Arrays.asList(Type.CONTAINING, Type.STARTING_WITH,
             Type.ENDING_WITH, Type.LIKE);
 
+        /** */
         private final Type type;
 
         /**
@@ -750,7 +745,6 @@ class StringQuery implements DeclaredQuery {
          */
         @Nullable
         @Override public Object prepare(@Nullable Object value) {
-
             if (value == null)
                 return null;
 
@@ -767,12 +761,8 @@ class StringQuery implements DeclaredQuery {
             }
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
+        /** */
         @Override public boolean equals(Object obj) {
-
             if (!(obj instanceof LikeParameterBinding))
                 return false;
 
@@ -781,10 +771,7 @@ class StringQuery implements DeclaredQuery {
             return super.equals(obj) && type.equals(that.type);
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#hashCode()
-         */
+        /** */
         @Override public int hashCode() {
 
             int result = super.hashCode();
@@ -794,10 +781,7 @@ class StringQuery implements DeclaredQuery {
             return result;
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#toString()
-         */
+        /** */
         @Override public String toString() {
             return String.format("LikeBinding [name: %s, position: %d, type: %s]", getName(), getPosition(), type);
         }
@@ -825,13 +809,12 @@ class StringQuery implements DeclaredQuery {
 
     }
 
+    /** */
     static class Metadata {
-
         /**
          * Uses jdbc style parameters.
          */
         private boolean usesJdbcStyleParameters;
-
     }
 
     /**
@@ -840,12 +823,12 @@ class StringQuery implements DeclaredQuery {
      *
      * @author Jens Schauder
      * @author Oliver Gierke
-     * @since 2.1
      */
     static class QuotationMap {
-
+        /** */
         private static final Collection<Character> QUOTING_CHARACTERS = Arrays.asList('"', '\'');
 
+        /** */
         private final List<Range<Integer>> quotedRanges = new ArrayList<>();
 
         /**
@@ -854,7 +837,6 @@ class StringQuery implements DeclaredQuery {
          * @param query can be {@literal null}.
          */
         public QuotationMap(@Nullable String query) {
-
             if (query == null)
                 return;
 
@@ -862,18 +844,15 @@ class StringQuery implements DeclaredQuery {
             int start = 0;
 
             for (int i = 0; i < query.length(); i++) {
-
                 char currentChar = query.charAt(i);
 
                 if (QUOTING_CHARACTERS.contains(currentChar)) {
-
                     if (inQuotation == null) {
 
                         inQuotation = currentChar;
                         start = i;
                     }
                     else if (currentChar == inQuotation) {
-
                         inQuotation = null;
 
                         quotedRanges.add(Range.from(Bound.inclusive(start)).to(Bound.inclusive(i)));
@@ -896,7 +875,5 @@ class StringQuery implements DeclaredQuery {
         public boolean isQuoted(int idx) {
             return quotedRanges.stream().anyMatch(r -> r.contains(idx));
         }
-
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java
index f2b5e26..598b79a 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelEvaluator.java
@@ -32,27 +32,18 @@ import org.springframework.util.Assert;
  * @author Jens Schauder
  * @author Gerrit Meier
  * @author Oliver Gierke
- * @since spring data 2.1 - transition code (borrowed and adapted code from version 2.1)
  */
 public class SpelEvaluator {
-    /**
-     * Parser.
-     */
+    /** */
     private static final SpelExpressionParser PARSER = new SpelExpressionParser();
 
-    /**
-     * Evaluation context provider.
-     */
+    /** */
     private final EvaluationContextProvider evaluationCtxProvider;
 
-    /**
-     * Parameters.
-     */
+    /** */
     private final Parameters<?, ?> parameters;
 
-    /**
-     * Extractor.
-     */
+    /** */
     private final SpelExtractor extractor;
 
     /**
@@ -75,7 +66,6 @@ public class SpelEvaluator {
      * @return a map from parameter name to evaluated value. Guaranteed to be not {@literal null}.
      */
     public Map<String, Object> evaluate(Object[] values) {
-
         Assert.notNull(values, "Values must not be null.");
 
         EvaluationContext evaluationCtx = evaluationCtxProvider.getEvaluationContext(parameters, values);
@@ -103,5 +93,4 @@ public class SpelEvaluator {
     private static Object getSpElValue(EvaluationContext evaluationCtx, String expression) {
         return PARSER.parseExpression(expression).getValue(evaluationCtx);
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java
index 579b36f..0684a5f 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/query/spel/SpelQueryContext.java
@@ -39,17 +39,12 @@ import org.springframework.util.Assert;
  *
  * @author Jens Schauder
  * @author Gerrit Meier
- * @since spring data 2.1 - transition code (borrowed and adapted code from version 2.1)
  */
 public class SpelQueryContext {
-    /**
-     * Spel pattern string.
-     */
+    /** */
     private static final String SPEL_PATTERN_STRING = "([:?])#\\{([^}]+)}";
 
-    /**
-     * Spel pattern.
-     */
+    /** */
     private static final Pattern SPEL_PATTERN = Pattern.compile(SPEL_PATTERN_STRING);
 
     /**
@@ -68,6 +63,7 @@ public class SpelQueryContext {
      */
     private final BiFunction<String, String, String> replacementSrc;
 
+    /** */
     private SpelQueryContext(BiFunction<Integer, String, String> paramNameSrc,
         BiFunction<String, String, String> replacementSrc) {
         this.paramNameSrc = paramNameSrc;
@@ -112,7 +108,6 @@ public class SpelQueryContext {
      * @return Evaluating Spel QueryContext
      */
     public EvaluatingSpelQueryContext withEvaluationContextProvider(EvaluationContextProvider provider) {
-
         Assert.notNull(provider, "EvaluationContextProvider must not be null!");
 
         return new EvaluatingSpelQueryContext(provider, paramNameSrc, replacementSrc);
@@ -123,10 +118,9 @@ public class SpelQueryContext {
      * {@link EvaluationContextProvider}.
      *
      * @author Oliver Gierke
-     * @since 2.1
      */
     public static class EvaluatingSpelQueryContext extends SpelQueryContext {
-
+        /** */
         private final EvaluationContextProvider evaluationContextProvider;
 
         /**
@@ -139,7 +133,6 @@ public class SpelQueryContext {
          */
         private EvaluatingSpelQueryContext(EvaluationContextProvider evaluationCtxProvider,
             BiFunction<Integer, String, String> paramNameSrc, BiFunction<String, String, String> replacementSrc) {
-
             super(paramNameSrc, replacementSrc);
 
             evaluationContextProvider = evaluationCtxProvider;
@@ -174,33 +167,21 @@ public class SpelQueryContext {
      *
      * @author Jens Schauder
      * @author Oliver Gierke
-     * @since 2.1
      */
     public class SpelExtractor {
-
-        /**
-         * Prefix group index.
-         */
+        /** */
         private static final int PREFIX_GROUP_INDEX = 1;
 
-        /**
-         * Expression group index.
-         */
+        /** */
         private static final int EXPRESSION_GROUP_INDEX = 2;
 
-        /**
-         * Query.
-         */
+        /** */
         private final String query;
 
-        /**
-         * Expressions.
-         */
+        /** */
         private final Map<String, String> expressions;
 
-        /**
-         * Quotations.
-         */
+        /** */
         private final QuotationMap quotations;
 
         /**
@@ -209,7 +190,6 @@ public class SpelQueryContext {
          * @param qry must not be {@literal null}.
          */
         SpelExtractor(String qry) {
-
             Assert.notNull(qry, "Query must not be null");
 
             Map<String, String> exps = new HashMap<>();
@@ -221,11 +201,10 @@ public class SpelQueryContext {
             int matchedUntil = 0;
 
             while (matcher.find()) {
-
                 if (quotedAreas.isQuoted(matcher.start()))
                     resultQry.append(qry, matchedUntil, matcher.end());
-                else {
 
+                else {
                     String spelExpression = matcher.group(EXPRESSION_GROUP_INDEX);
                     String prefix = matcher.group(PREFIX_GROUP_INDEX);
 
@@ -303,18 +282,12 @@ public class SpelQueryContext {
      *
      * @author Jens Schauder
      * @author Oliver Gierke
-     * @since 2.1
      */
     static class QuotationMap {
-
-        /**
-         * Quoting characters.
-         */
+        /** */
         private static final Collection<Character> QUOTING_CHARACTERS = Arrays.asList('"', '\'');
 
-        /**
-         * Quoted ranges.
-         */
+        /** */
         private final List<Range<Integer>> quotedRanges = new ArrayList<>();
 
         /**
@@ -323,7 +296,6 @@ public class SpelQueryContext {
          * @param qry can be {@literal null}.
          */
         public QuotationMap(@Nullable String qry) {
-
             if (qry == null)
                 return;
 
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java
index f77f220..1b4b378 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/ConditionFalse.java
@@ -25,9 +25,7 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
  * Always false condition. Tells spring context never load bean with such Condition.
  */
 public class ConditionFalse implements Condition {
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
         return false;
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
index be83460..ac8d175 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
@@ -101,6 +101,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         beanExpressionContext = new BeanExpressionContext(beanFactory, null);
     }
 
+    /** */
     private Ignite igniteForRepoConfig(RepositoryConfig config) {
         try {
             String igniteInstanceName = evaluateExpression(config.igniteInstance());
@@ -135,39 +136,27 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         }
     }
 
-    /**
-     * {@inheritDoc} @param <T>  the type parameter
-     *
-     * @param <ID>        the type parameter
-     * @param domainClass the domain class
-     * @return the entity information
-     */
+    /** {@inheritDoc} */
     @Override public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
         return new AbstractEntityInformation<T, ID>(domainClass) {
+            /** {@inheritDoc} */
             @Override public ID getId(T entity) {
                 return null;
             }
 
+            /** {@inheritDoc} */
             @Override public Class<ID> getIdType() {
                 return null;
             }
         };
     }
 
-    /**
-     * {@inheritDoc} @param metadata the metadata
-     *
-     * @return the repository base class
-     */
+    /** {@inheritDoc} */
     @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
         return IgniteRepositoryImpl.class;
     }
 
-    /**
-     * {@inheritDoc} @param repoItf the repo itf
-     *
-     * @return the repository metadata
-     */
+    /** {@inheritDoc} */
     @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
         Assert.notNull(repoItf, "Repository interface must be set.");
         Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
@@ -190,7 +179,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
     }
 
     /**
-     * evaluate the SpEL expression
+     * Evaluate the SpEL expression
      *
      * @param spelExpression SpEL expression
      * @return the result of execution of the SpEL expression
@@ -200,7 +189,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         return (String)resolver.evaluate(spelExpression, beanExpressionContext);
     }
 
-    /* control underline cache creation to avoid cache creation by mistake */
+    /** Control underlying cache creation to avoid cache creation by mistake */
     private IgniteCache getRepositoryCache(Class<?> repoIf) {
         Ignite ignite = repoToIgnite.get(repoIf);
 
@@ -221,27 +210,18 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         return c;
     }
 
-    /**
-     * {@inheritDoc} @param metadata the metadata
-     *
-     * @return the target repository
-     */
+    /** {@inheritDoc} */
     @Override protected Object getTargetRepository(RepositoryInformation metadata) {
         Ignite ignite = repoToIgnite.get(metadata.getRepositoryInterface());
+
         return getTargetRepositoryViaReflection(metadata, ignite,
             getRepositoryCache(metadata.getRepositoryInterface()));
     }
 
-    /**
-     * {@inheritDoc} @param key the key
-     *
-     * @param evaluationContextProvider the evaluation context provider
-     * @return the query lookup strategy
-     */
+    /** {@inheritDoc} */
     @Override protected Optional<QueryLookupStrategy> getQueryLookupStrategy(final QueryLookupStrategy.Key key,
         EvaluationContextProvider evaluationContextProvider) {
         return Optional.of((mtd, metadata, factory, namedQueries) -> {
-
             final Query annotation = mtd.getAnnotation(Query.class);
             final Ignite ignite = repoToIgnite.get(metadata.getRepositoryInterface());
 
@@ -249,11 +229,14 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
                 .dynamicQuery())) {
 
                 String qryStr = annotation.value();
+
                 boolean annotatedIgniteQuery = !annotation.dynamicQuery() && (StringUtils.hasText(qryStr) || annotation
                     .textQuery());
+
                 IgniteQuery query = annotatedIgniteQuery ? new IgniteQuery(qryStr,
                     !annotation.textQuery() && (isFieldQuery(qryStr) || annotation.forceFieldsQuery()),
                     annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
+
                 if (key != QueryLookupStrategy.Key.CREATE) {
                     return new IgniteRepositoryQuery(ignite, metadata, query, mtd, factory,
                         getRepositoryCache(metadata.getRepositoryInterface()),
@@ -302,5 +285,4 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
             // insert
             qryUpperCase.matches("^\\s*INSERT\\b.*");
     }
-
 }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
index fa94574..5b3d612 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
@@ -45,9 +45,7 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
  */
 public class IgniteRepositoryFactoryBean<T extends Repository<V, K>, V, K extends Serializable>
     extends RepositoryFactoryBeanSupport<T, V, K> implements ApplicationContextAware {
-    /**
-     * Application context.
-     */
+    /** */
     private ApplicationContext ctx;
 
     /**
@@ -57,16 +55,12 @@ public class IgniteRepositoryFactoryBean<T extends Repository<V, K>, V, K extend
         super(repoInterface);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
         this.ctx = ctx;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected RepositoryFactorySupport createRepositoryFactory() {
         return new IgniteRepositoryFactory(ctx);
     }
diff --git a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
index 3c32f7b..44156a7 100644
--- a/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.0/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
@@ -65,53 +65,31 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         this.ignite = ignite;
     }
 
-    /**
-     * {@inheritDoc} @return the ignite cache
-     */
+    /** {@inheritDoc} */
     @Override public IgniteCache<K, V> cache() {
         return cache;
     }
 
-    /**
-     * {@inheritDoc} @return the ignite
-     */
+    /** {@inheritDoc} */
     @Override public Ignite ignite() {
         return ignite;
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param key    the key
-     * @param entity the entity
-     * @return the s
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> S save(K key, S entity) {
         cache.put(key, entity);
 
         return entity;
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entities the entities
-     * @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> Iterable<S> save(Map<K, S> entities) {
         cache.putAll(entities);
 
         return entities.values();
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param key       the key
-     * @param entity    the entity
-     * @param expiryPlc the expiry policy
-     * @return the s
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> S save(K key, S entity, @Nullable ExpiryPolicy expiryPlc) {
         if (expiryPlc != null)
             cache.withExpiryPolicy(expiryPlc).put(key, entity);
@@ -120,13 +98,7 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         return entity;
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entities  the entities
-     * @param expiryPlc the expiry policy
-     * @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> Iterable<S> save(Map<K, S> entities, @Nullable ExpiryPolicy expiryPlc) {
         if (expiryPlc != null)
             cache.withExpiryPolicy(expiryPlc).putAll(entities);
@@ -136,60 +108,48 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
     }
 
     /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entity the entity
-     * @return the s
+     * Not implemented.
      */
     @Override public <S extends V> S save(S entity) {
         throw new UnsupportedOperationException("Use IgniteRepository.save(key,value) method instead.");
     }
 
     /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entities the entities
-     * @return the iterable
+     * Not implemented.
      */
     @Override public <S extends V> Iterable<S> saveAll(Iterable<S> entities) {
         throw new UnsupportedOperationException("Use IgniteRepository.save(Map<keys,value>) method instead.");
     }
 
-    /**
-     * {@inheritDoc} @param id the id
-     *
-     * @return the optional
-     */
+    /** {@inheritDoc} */
     @Override public Optional<V> findById(K id) {
         return Optional.ofNullable(cache.get(id));
     }
 
-    /**
-     * {@inheritDoc} @param id the id
-     *
-     * @return the boolean
-     */
+    /** {@inheritDoc} */
     @Override public boolean existsById(K id) {
         return cache.containsKey(id);
     }
 
-    /**
-     * {@inheritDoc} @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public Iterable<V> findAll() {
         final Iterator<Cache.Entry<K, V>> iter = cache.iterator();
 
         return new Iterable<V>() {
+            /** */
             @Override public Iterator<V> iterator() {
                 return new Iterator<V>() {
+                    /** {@inheritDoc} */
                     @Override public boolean hasNext() {
                         return iter.hasNext();
                     }
 
+                    /** {@inheritDoc} */
                     @Override public V next() {
                         return iter.next().getValue();
                     }
 
+                    /** {@inheritDoc} */
                     @Override public void remove() {
                         iter.remove();
                     }
@@ -198,11 +158,7 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         };
     }
 
-    /**
-     * {@inheritDoc} @param ids the ids
-     *
-     * @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public Iterable<V> findAllById(Iterable<K> ids) {
         if (ids instanceof Set)
             return cache.getAll((Set<K>)ids).values();
@@ -218,37 +174,27 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         return cache.getAll(keys).values();
     }
 
-    /**
-     * {@inheritDoc} @return the long
-     */
+    /** {@inheritDoc} */
     @Override public long count() {
         return cache.size(CachePeekMode.PRIMARY);
     }
 
-    /**
-     * {@inheritDoc} @param id the id
-     */
+    /** {@inheritDoc} */
     @Override public void deleteById(K id) {
         cache.remove(id);
     }
 
-    /**
-     * {@inheritDoc} @param entity the entity
-     */
+    /** {@inheritDoc} */
     @Override public void delete(V entity) {
         throw new UnsupportedOperationException("Use IgniteRepository.deleteById(key) method instead.");
     }
 
-    /**
-     * {@inheritDoc} @param entities the entities
-     */
+    /** {@inheritDoc} */
     @Override public void deleteAll(Iterable<? extends V> entities) {
         throw new UnsupportedOperationException("Use IgniteRepository.deleteAllById(keys) method instead.");
     }
 
-    /**
-     * {@inheritDoc} @param ids the ids
-     */
+    /** {@inheritDoc} */
     @Override public void deleteAllById(Iterable<K> ids) {
         if (ids instanceof Set) {
             cache.removeAll((Set<K>)ids);
@@ -268,11 +214,8 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         cache.removeAll(keys);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public void deleteAll() {
         cache.clear();
     }
-
 }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
index 47417ee..5841f41 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
@@ -31,30 +31,20 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
  * Test with using repository which is configured by Spring EL
  */
 public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTest {
-    /**
-     * Number of entries to store
-     */
+    /** Number of entries to store */
     private static final int CACHE_SIZE = 1000;
 
-    /**
-     * Repository.
-     */
+    /** Repository. */
     private static PersonExpressionRepository repo;
 
-    /**
-     * Context.
-     */
+    /** Context. */
     private static AnnotationConfigApplicationContext ctx;
 
-    /**
-     *
-     */
+    /** */
     @Rule
     public final ExpectedException expected = ExpectedException.none();
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
@@ -65,9 +55,7 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         repo = ctx.getBean(PersonExpressionRepository.class);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
 
@@ -76,9 +64,7 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         assertEquals(CACHE_SIZE, repo.count());
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         repo.deleteAll();
 
@@ -87,25 +73,21 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         super.afterTest();
     }
 
-    /**
-     *
-     */
+    /** */
     private void fillInRepository() {
         for (int i = 0; i < CACHE_SIZE - 5; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
                 "lastName" + Integer.toHexString((i + 16) % 256)));
         }
 
-        repo.save((int)repo.count(), new Person("uniquePerson", "uniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("uniquePerson", "uniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void afterTestsStopped() {
         ctx.close();
     }
@@ -146,6 +128,7 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
             cacheNames.contains("PersonCache"));
     }
 
+    /** */
     @Test
     public void testCacheCountTWO() {
         Ignite ignite = ctx.getBean("igniteInstanceTWO", Ignite.class);
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
index 5b52092..38785ef 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
@@ -33,7 +33,7 @@ import org.junit.Test;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
 /**
- *
+ * CRUD tests.
  */
 public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     /** Repository. */
@@ -76,9 +76,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         super.afterTest();
     }
 
-    /**
-     *
-     */
+    /** */
     private void fillInRepository() {
         for (int i = 0; i < CACHE_SIZE - 5; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
@@ -97,9 +95,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         ctx.destroy();
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testPutGet() {
         Person person = new Person("some_name", "some_surname");
@@ -122,9 +118,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testPutAllGetAll() {
         LinkedHashMap<Integer, Person> map = new LinkedHashMap<>();
@@ -162,9 +156,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(map.size(), counter);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testGetAll() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -181,9 +173,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(repo.count(), counter);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testDelete() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -203,9 +193,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testDeleteSet() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -234,9 +222,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testDeleteAll() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -247,7 +233,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete existing record
+     * Delete existing record.
      */
     @Test
     public void testDeleteByFirstName() {
@@ -259,7 +245,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete NON existing record
+     * Delete NON existing record.
      */
     @Test
     public void testDeleteExpression() {
@@ -269,7 +255,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete Multiple records due to where
+     * Delete Multiple records due to where.
      */
     @Test
     public void testDeleteExpressionMultiple() {
@@ -280,7 +266,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Remove should do the same than Delete
+     * Remove should do the same than Delete.
      */
     @Test
     public void testRemoveExpression() {
@@ -291,7 +277,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete unique record using lower case key word
+     * Delete unique record using lower case key word.
      */
     @Test
     public void testDeleteQuery() {
@@ -302,7 +288,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Try to delete with a wrong @Query
+     * Try to delete with a wrong @Query.
      */
     @Test
     public void testWrongDeleteQuery() {
@@ -320,7 +306,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Update with a @Query a record
+     * Update with a @Query a record.
      */
     @Test
     public void testUpdateQueryMixedCase() {
@@ -347,6 +333,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName1");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionNamedParameter() {
         final String newSecondName = "updatedUniqueSecondName2";
@@ -358,6 +345,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseDynamicProjectionNamedParameter() {
         final String newSecondName = "updatedUniqueSecondName2";
@@ -372,6 +360,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(personFullName.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
+    /** */
     @Test
     public void testUpdateQueryOneMixedCaseDynamicProjectionNamedParameter() {
         final String newSecondName = "updatedUniqueSecondName2";
@@ -386,6 +375,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(personFullName.getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionIndexedParameter() {
         final String newSecondName = "updatedUniqueSecondName3";
@@ -397,6 +387,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName3");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionIndexedParameterLuceneTextQuery() {
         final String newSecondName = "updatedUniqueSecondName4";
@@ -408,6 +399,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName4");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionNamedParameterAndTemplateDomainEntityVariable() {
         final String newSecondName = "updatedUniqueSecondName5";
@@ -419,6 +411,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName5");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionNamedParameterWithSpELExtension() {
         final String newSecondName = "updatedUniqueSecondName6";
@@ -438,6 +431,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     public void testWrongUpdateQuery() {
         final String newSecondName = "updatedUniqueSecondName";
         int rowsUpdated = 0;
+
         try {
             rowsUpdated = repo.setWrongFixedSecondName(newSecondName, "uniquePerson");
         }
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
index 03b15a6..9c16f6d 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
@@ -38,14 +38,10 @@ import org.springframework.data.domain.Sort;
  *
  */
 public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
-    /**
-     * Repository.
-     */
+    /** Repository. */
     private static PersonRepository repo;
 
-    /**
-     * Repository 2.
-     */
+    /** Repository 2. */
     private static PersonSecondRepository repo2;
 
     /**
@@ -53,9 +49,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
      */
     private static PersonRepositoryOtherIgniteInstance repoTWO;
 
-    /**
-     * Context.
-     */
+    /** Context. */
     private static AnnotationConfigApplicationContext ctx;
 
     /**
@@ -95,9 +89,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         ctx.destroy();
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testExplicitQuery() {
         List<Person> persons = repo.simpleQuery("person4a");
@@ -108,6 +100,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("person4a", person.getFirstName());
     }
 
+    /** */
     @Test
     public void testExplicitQueryTWO() {
         List<Person> persons = repoTWO.simpleQuery("TWOperson4a");
@@ -118,9 +111,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("TWOperson4a", person.getFirstName());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testEqualsPart() {
         List<Person> persons = repo.findByFirstName("person4e");
@@ -131,6 +122,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("person4e", person.getFirstName());
     }
 
+    /** */
     @Test
     public void testEqualsPartTWO() {
         List<Person> persons = repoTWO.findByFirstName("TWOperson4e");
@@ -141,9 +133,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("TWOperson4e", person.getFirstName());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testContainingPart() {
         List<Person> persons = repo.findByFirstNameContaining("person4");
@@ -154,6 +144,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(person.getFirstName().startsWith("person4"));
     }
 
+    /** */
     @Test
     public void testContainingPartTWO() {
         List<Person> persons = repoTWO.findByFirstNameContaining("TWOperson4");
@@ -164,9 +155,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(person.getFirstName().startsWith("TWOperson4"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testTopPart() {
         Iterable<Person> top = repo.findTopByFirstNameContaining("person4");
@@ -180,6 +169,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFirstName().startsWith("person4"));
     }
 
+    /** */
     @Test
     public void testTopPartTWO() {
         Iterable<Person> top = repoTWO.findTopByFirstNameContaining("TWOperson4");
@@ -193,9 +183,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFirstName().startsWith("TWOperson4"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testLikeAndLimit() {
         Iterable<Person> like = repo.findFirst10ByFirstNameLike("person");
@@ -211,6 +199,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, cnt);
     }
 
+    /** */
     @Test
     public void testLikeAndLimitTWO() {
         Iterable<Person> like = repoTWO.findFirst10ByFirstNameLike("TWOperson");
@@ -226,9 +215,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, cnt);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testCount() {
         int cnt = repo.countByFirstNameLike("person");
@@ -236,6 +223,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(1000, cnt);
     }
 
+    /** */
     @Test
     public void testCountTWO() {
         int cnt = repoTWO.countByFirstNameLike("TWOperson");
@@ -243,9 +231,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(1000, cnt);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testCount2() {
         int cnt = repo.countByFirstNameLike("person4");
@@ -253,6 +239,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cnt < 1000);
     }
 
+    /** */
     @Test
     public void testCount2TWO() {
         int cnt = repoTWO.countByFirstNameLike("TWOperson4");
@@ -260,9 +247,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cnt < 1000);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testPageable() {
         PageRequest pageable = new PageRequest(1, 5, Sort.Direction.DESC, "firstName");
@@ -292,9 +277,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, firstNames.size());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testAndAndOr() {
         int cntAnd = repo.countByFirstNameLikeAndSecondNameLike("person1", "lastName1");
@@ -304,9 +287,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cntAnd <= cntOr);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testQueryWithSort() {
         List<Person> persons = repo.queryWithSort("^[a-z]+$", new Sort(Sort.Direction.DESC, "secondName"));
@@ -322,9 +303,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testQueryWithPaging() {
         List<Person> persons = repo.queryWithPageable("^[a-z]+$", new PageRequest(1, 7, Sort.Direction.DESC, "secondName"));
@@ -342,9 +321,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testQueryFields() {
         List<String> persons = repo.selectField("^[a-z]+$", new PageRequest(1, 7, Sort.Direction.DESC, "secondName"));
@@ -352,9 +329,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(7, persons.size());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testFindCacheEntries() {
         List<Cache.Entry<Integer, Person>> cacheEntries = repo.findBySecondNameLike("stName1");
@@ -365,9 +340,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(entry.getValue().getSecondName().contains("stName1"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testFindOneCacheEntry() {
         Cache.Entry<Integer, Person> cacheEntry = repo.findTopBySecondNameLike("tName18");
@@ -377,9 +350,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cacheEntry.getValue().getSecondName().contains("tName18"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testFindOneValue() {
         PersonProjection person = repo.findTopBySecondNameStartingWith("lastName18");
@@ -389,9 +360,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFullName().split("\\s")[1].startsWith("lastName18"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testSelectSeveralFields() {
         List<List> lists = repo.selectSeveralField("^[a-z]+$", new PageRequest(2, 6));
@@ -405,9 +374,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testCountQuery() {
         int cnt = repo.countQuery(".*");
@@ -415,9 +382,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(256, cnt);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testSliceOfCacheEntries() {
         Slice<Cache.Entry<Integer, Person>> slice = repo2.findBySecondNameIsNot("lastName18", new PageRequest(3, 4));
@@ -428,9 +393,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertFalse("lastName18".equals(entry.getValue().getSecondName()));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testSliceOfLists() {
         Slice<List> lists = repo2.querySliceOfList("^[a-z]+$", new PageRequest(0, 3));
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
index 5ee327f..bce3340 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
@@ -29,15 +29,14 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.repository.query.spi.EvaluationContextExtension;
 
-/**
- *
- */
+/** */
 @Configuration
 @EnableIgniteRepositories
 public class ApplicationConfiguration {
-
+    /** */
     public static final String IGNITE_INSTANCE_ONE = "IGNITE_INSTANCE_ONE";
 
+    /** */
     public static final String IGNITE_INSTANCE_TWO = "IGNITE_INSTANCE_TWO";
 
     /**
@@ -52,11 +51,13 @@ public class ApplicationConfiguration {
         return bean;
     }
 
+    /** */
     @Bean
     public EvaluationContextExtension sampleSpELExtension() {
         return new SampleEvaluationContextExtension();
     }
 
+    /** */
     @Bean(value = "sampleExtensionBean")
     public SamplePassParamExtension sampleExtensionBean() {
         return new SamplePassParamExtension();
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
index 9aca003..23f8f8e 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
@@ -24,7 +24,6 @@ import org.springframework.beans.factory.annotation.Value;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public interface FullNameProjection {
-
     /**
      * Sample of using SpEL expression
      * @return
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
index c4cab06..a187a08 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
@@ -24,7 +24,7 @@ import org.springframework.beans.factory.annotation.Value;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public interface PersonProjection {
-
+    /** */
     String getFirstName();
 
     /**
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
index 7cb437d..917d16a 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
@@ -27,7 +27,7 @@ import org.apache.ignite.springdata20.repository.IgniteRepository;
 import org.springframework.data.repository.query.Param;
 
 /**
- *
+ * Test repository.
  */
 @RepositoryConfig(cacheName = "PersonCache")
 public interface PersonRepository extends IgniteRepository<Person, Integer> {
diff --git a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
index 0e6356a..0fa535d 100644
--- a/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
+++ b/modules/spring-data-2.0/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
@@ -59,32 +59,34 @@ import org.springframework.data.repository.query.spi.EvaluationContextExtensionS
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public class SampleEvaluationContextExtension extends EvaluationContextExtensionSupport {
-
+    /** */
     private static final SamplePassParamExtension SAMPLE_PASS_PARAM_EXTENSION_INSTANCE = new SamplePassParamExtension();
 
+    /** */
     private static final Map<String, Object> properties = new HashMap<>();
 
+    /** */
     private static final String SAMPLE_EXTENSION_SPEL_VAR = "sampleExtension";
 
     static {
         properties.put(SAMPLE_EXTENSION_SPEL_VAR, SAMPLE_PASS_PARAM_EXTENSION_INSTANCE);
     }
 
+    /** */
     @Override public String getExtensionId() {
         return "HK-SAMPLE-PASS-PARAM-EXTENSION";
     }
 
+    /** */
     @Override public Map<String, Object> getProperties() {
         return properties;
     }
 
+    /** */
     public static class SamplePassParamExtension {
-
         // just return same param
         public Object transformParam(Object param) {
             return param;
         }
-
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java
index b81992e..3cc3172 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/IgniteRepository.java
@@ -66,7 +66,7 @@ public interface IgniteRepository<V, K extends Serializable> extends CrudReposit
      * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
      * (keys) that are not unique cluster wide.
      *
-     * @param <S>      type of entities.
+     * @param <S>      Type of entities.
      * @param entities Map of key-entities pairs to save.
      * @return Saved entities.
      */
@@ -92,7 +92,7 @@ public interface IgniteRepository<V, K extends Serializable> extends CrudReposit
      * It's suggested to use this method instead of default {@link CrudRepository#save(Object)} that generates IDs
      * (keys) that are not unique cluster wide.
      *
-     * @param <S>       type of entities.
+     * @param <S>       Type of entities.
      * @param entities  Map of key-entities pairs to save.
      * @param expiryPlc ExpiryPolicy to apply, if not null.
      * @return Saved entities.
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java
index eed1b4d..f915267 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/DynamicQueryConfig.java
@@ -31,64 +31,37 @@ package org.apache.ignite.springdata22.repository.config;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public class DynamicQueryConfig {
-    /**
-     * Value.
-     */
+    /** */
     private String value = "";
 
-    /**
-     * Text query.
-     */
+    /** */
     private boolean textQuery;
 
-    /**
-     * Force fields query.
-     */
+    /** */
     private boolean forceFieldsQry;
 
-    /**
-     * Collocated.
-     */
+    /** */
     private boolean collocated;
 
-    /**
-     * Timeout.
-     */
+    /** */
     private int timeout;
 
-    /**
-     * Enforce join order.
-     */
+    /** */
     private boolean enforceJoinOrder;
 
-    /**
-     * Distributed joins.
-     */
+    /** */
     private boolean distributedJoins;
 
-    /**
-     * Replicated only.
-     */
-    private boolean replicatedOnly;
-
-    /**
-     * Lazy.
-     */
+    /** */
     private boolean lazy;
 
-    /**
-     * Local.
-     */
+    /** */
     private boolean local;
 
-    /**
-     * Parts.
-     */
+    /** */
     private int[] parts;
 
-    /**
-     * Limit.
-     */
+    /** */
     private int limit;
 
     /**
@@ -105,7 +78,6 @@ public class DynamicQueryConfig {
             config.timeout = queryConfiguration.timeout();
             config.enforceJoinOrder = queryConfiguration.enforceJoinOrder();
             config.distributedJoins = queryConfiguration.distributedJoins();
-            config.replicatedOnly = queryConfiguration.replicatedOnly();
             config.lazy = queryConfiguration.lazy();
             config.parts = queryConfiguration.parts();
             config.local = queryConfiguration.local();
@@ -201,19 +173,6 @@ public class DynamicQueryConfig {
     }
 
     /**
-     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
-     * <p>
-     * Only applicable to SqlFieldsQuery and SqlQuery
-     *
-     * @return the boolean
-     * @deprecated No longer used as of Apache Ignite 2.8.
-     */
-    @Deprecated
-    public boolean replicatedOnly() {
-        return replicatedOnly;
-    }
-
-    /**
      * Sets lazy query execution flag.
      * <p>
      * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
@@ -344,17 +303,6 @@ public class DynamicQueryConfig {
     }
 
     /**
-     * Sets replicated only.
-     *
-     * @param replicatedOnly the replicated only
-     * @return this for chaining
-     */
-    public DynamicQueryConfig setReplicatedOnly(boolean replicatedOnly) {
-        this.replicatedOnly = replicatedOnly;
-        return this;
-    }
-
-    /**
      * Sets lazy.
      *
      * @param lazy the lazy
@@ -397,5 +345,4 @@ public class DynamicQueryConfig {
         this.limit = limit;
         return this;
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java
index 416ec0b..ddecd77 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoriesRegistar.java
@@ -25,16 +25,12 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryBeanDefinitionRegistrarSupport}.
  */
 public class IgniteRepositoriesRegistar extends RepositoryBeanDefinitionRegistrarSupport {
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected Class<? extends Annotation> getAnnotation() {
         return EnableIgniteRepositories.class;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected RepositoryConfigurationExtension getExtension() {
         return new IgniteRepositoryConfigurationExtension();
     }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
index b78811b..4989196 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -27,30 +27,22 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getModuleName() {
         return "Apache Ignite";
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected String getModulePrefix() {
         return "ignite";
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getRepositoryFactoryBeanClassName() {
         return IgniteRepositoryFactoryBean.class.getName();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
         return Collections.singleton(IgniteRepository.class);
     }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java
index a3b3a51..d1af467 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/config/Query.java
@@ -89,16 +89,6 @@ public @interface Query {
     boolean distributedJoins() default false;
 
     /**
-     * Specify if the query contains only replicated tables. This is a hint for potentially more effective execution.
-     * <p>
-     * Only applicable to SqlFieldsQuery and SqlQuery
-     *
-     * @deprecated No longer used as of Apache Ignite 2.8.
-     */
-    @Deprecated
-    boolean replicatedOnly() default false;
-
-    /**
      * Sets lazy query execution flag.
      * <p>
      * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. For small and
@@ -143,5 +133,4 @@ public @interface Query {
      * Sets limit to response records count for TextQuery. If 0 or less, considered to be no limit.
      */
     int limit() default 0;
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java
index e6ad7ba..e968034 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/DeclaredQuery.java
@@ -23,7 +23,6 @@ import org.springframework.util.StringUtils;
  * A wrapper for a String representation of a query offering information about the query.
  *
  * @author Jens Schauder
- * @since 2.0.3
  */
 interface DeclaredQuery {
     /**
@@ -56,8 +55,6 @@ interface DeclaredQuery {
 
     /**
      * Returns whether the query is using a constructor expression.
-     *
-     * @since 1.10
      */
     public boolean hasConstructorExpression();
 
@@ -84,7 +81,6 @@ interface DeclaredQuery {
 
     /**
      * @return whether paging is implemented in the query itself, e.g. using SpEL expressions.
-     * @since 2.0.6
      */
     public default boolean usesPaging() {
         return false;
@@ -95,7 +91,6 @@ interface DeclaredQuery {
      * name.
      *
      * @return Whether the query uses JDBC style parameters.
-     * @since 2.0.6
      */
     public boolean usesJdbcStyleParameters();
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java
index dcf06b4..47691b6 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/EmptyDeclaredQuery.java
@@ -24,7 +24,6 @@ import org.springframework.util.Assert;
  * NULL-Object pattern implementation for {@link DeclaredQuery}.
  *
  * @author Jens Schauder
- * @since 2.0.3
  */
 class EmptyDeclaredQuery implements DeclaredQuery {
     /**
@@ -32,59 +31,43 @@ class EmptyDeclaredQuery implements DeclaredQuery {
      */
     static final DeclaredQuery EMPTY_QUERY = new EmptyDeclaredQuery();
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean hasNamedParameter() {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getQueryString() {
         return "";
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public String getAlias() {
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean hasConstructorExpression() {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean isDefaultProjection() {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public List<StringQuery.ParameterBinding> getParameterBindings() {
         return Collections.emptyList();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public DeclaredQuery deriveCountQuery(@Nullable String cntQry, @Nullable String cntQryProjection) {
         Assert.hasText(cntQry, "CountQuery must not be empty!");
         return DeclaredQuery.of(cntQry);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean usesJdbcStyleParameters() {
         return false;
     }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java
index 4e6007a..bdbd81d 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/ExpressionBasedStringQuery.java
@@ -150,5 +150,4 @@ class ExpressionBasedStringQuery extends StringQuery {
     private static boolean containsExpression(String qry) {
         return qry.contains(ENTITY_NAME_VARIABLE_EXPRESSION);
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java
index 5b552af..49c947d 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQuery.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.springdata22.repository.query;
 
-import java.util.StringJoiner;
+import org.apache.ignite.internal.util.typedef.internal.S;
 
 /**
  * Ignite query helper class. For internal use only.
@@ -26,24 +26,15 @@ import java.util.StringJoiner;
  * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteQuery {
-
-    /**
-     *
-     */
+    /** */
     enum Option {
-        /**
-         * Query will be used with Sort object.
-         */
+        /** Query will be used with Sort object. */
         SORTING,
 
-        /**
-         * Query will be used with Pageable object.
-         */
+        /** Query will be used with Pageable object. */
         PAGINATION,
 
-        /**
-         * No advanced option.
-         */
+        /** No advanced option. */
         NONE
     }
 
@@ -136,10 +127,8 @@ public class IgniteQuery {
         return option;
     }
 
+    /** */
     @Override public String toString() {
-        return new StringJoiner(", ", IgniteQuery.class.getSimpleName() + "[", "]").add("qrySql='" + qrySql + "'")
-            .add("isFieldQuery=" + isFieldQuery).add("isTextQuery=" + isTextQuery)
-            .add("isAutogenerated=" + isAutogenerated).add("option=" + option).toString();
+        return S.toString(IgniteQuery.class, this);
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java
index 9772e45..48b070d 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteQueryGenerator.java
@@ -29,8 +29,9 @@ import org.springframework.data.repository.query.parser.PartTree;
  * Ignite query generator for Spring Data framework.
  */
 public class IgniteQueryGenerator {
-
+    /** */
     private IgniteQueryGenerator() {
+        // No-op.
     }
 
     /**
@@ -38,7 +39,6 @@ public class IgniteQueryGenerator {
      * @param metadata Metadata.
      * @return Generated ignite query.
      */
-    @NotNull
     public static IgniteQuery generateSql(Method mtd, RepositoryMetadata metadata) {
         PartTree parts = new PartTree(mtd.getName(), metadata.getDomainType());
 
@@ -253,5 +253,4 @@ public class IgniteQueryGenerator {
 
         sql.append(")");
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java
index c51c984..8ddbe51 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/IgniteRepositoryQuery.java
@@ -33,7 +33,6 @@ import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.stream.Stream;
-
 import javax.cache.Cache;
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.ignite.Ignite;
@@ -156,166 +155,105 @@ import static org.apache.ignite.springdata22.repository.support.IgniteRepository
  * </pre>
  * </li>
  * </ol>
- * <p>
- * Visit <a href="https://docs.hawkore.com/private/apache-ignite-advanced-indexing">Apache Ignite advanced Indexing
- * Documentation site</a> for more info about Advanced Lucene Index and Lucene Query Builder.
  *
  * @author Apache Ignite Team
  * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 @SuppressWarnings("unchecked")
 public class IgniteRepositoryQuery implements RepositoryQuery {
-
+    /** */
     private static final TreeMap<String, Class<?>> binaryFieldClass = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     /**
      * Defines the way how to process query result
      */
     private enum ReturnStrategy {
-        /**
-         * Need to return only one value.
-         */
+        /** Need to return only one value. */
         ONE_VALUE,
 
-        /**
-         * Need to return one cache entry
-         */
+        /** Need to return one cache entry */
         CACHE_ENTRY,
 
-        /**
-         * Need to return list of cache entries
-         */
+        /** Need to return list of cache entries */
         LIST_OF_CACHE_ENTRIES,
 
-        /**
-         * Need to return list of values
-         */
+        /** Need to return list of values */
         LIST_OF_VALUES,
 
-        /**
-         * Need to return list of lists
-         */
+        /** Need to return list of lists */
         LIST_OF_LISTS,
 
-        /**
-         * Need to return slice
-         */
+        /** Need to return slice */
         SLICE_OF_VALUES,
 
-        /**
-         * Slice of cache entries.
-         */
+        /** Slice of cache entries */
         SLICE_OF_CACHE_ENTRIES,
 
-        /**
-         * Slice of lists.
-         */
+        /** Slice of lists */
         SLICE_OF_LISTS,
 
-        /**
-         * Need to return Page of values
-         */
+        /** Need to return Page of values */
         PAGE_OF_VALUES,
 
-        /**
-         * Need to return stream of values
-         */
+        /** Need to return stream of values */
         STREAM_OF_VALUES,
     }
 
-    /**
-     * Type.
-     */
+    /** */
     private final Class<?> type;
 
-    /**
-     * Sql.
-     */
+    /** */
     private final IgniteQuery staticQuery;
 
-    /**
-     * Cache.
-     */
+    /** */
     private final IgniteCache cache;
 
-    /**
-     * Ignite instance
-     */
+    /** */
     private final Ignite ignite;
 
-    /**
-     * required by qryStr field query type for binary manipulation
-     */
+    /** Required by qryStr field query type for binary manipulation */
     private IgniteBinaryImpl igniteBinary;
 
-    /**
-     * Ignite bin type.
-     */
+    /** */
     private BinaryType igniteBinType;
 
-    /**
-     * Method.
-     */
+    /** */
     private final Method mtd;
 
-    /**
-     * Metadata.
-     */
+    /** */
     private final RepositoryMetadata metadata;
 
-    /**
-     * Factory.
-     */
+    /** */
     private final ProjectionFactory factory;
 
-    /**
-     * Return strategy.
-     */
+    /** */
     private final ReturnStrategy staticReturnStgy;
 
-    /**
-     * Detect if returned data from method is projected
-     */
+    /** Detect if returned data from method is projected */
     private final boolean hasProjection;
 
-    /**
-     * Whether projection is dynamic (provided as method parameter)
-     */
+    /** Whether projection is dynamic (provided as method parameter) */
     private final boolean hasDynamicProjection;
 
-    /**
-     * Dynamic projection parameter index.
-     */
+    /** Dynamic projection parameter index */
     private final int dynamicProjectionIndex;
 
-    /**
-     * Dynamic query configuration.
-     */
+    /** Dynamic query configuration */
     private final int dynamicQueryConfigurationIndex;
 
-    /**
-     * the return query method
-     */
+    /** The return query method */
     private final QueryMethod qMethod;
 
-    /**
-     * the return domain class of QueryMethod
-     */
+    /** The return domain class of QueryMethod */
     private final Class<?> returnedDomainClass;
 
-    /**
-     * Expression parser.
-     */
+    /** */
     private final SpelExpressionParser expressionParser;
 
-    /**
-     * could provide ExtensionAwareQueryMethodEvaluationContextProvider
-     */
+    /** Could provide ExtensionAwareQueryMethodEvaluationContextProvider */
     private final QueryMethodEvaluationContextProvider queryMethodEvaluationContextProvider;
 
-    /**
-     * Static query configuration.
-     */
+    /** Static query configuration. */
     private final DynamicQueryConfig staticQueryConfiguration;
 
     /**
@@ -386,7 +324,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      * @return the object
      */
     @Override public Object execute(Object[] values) {
-
         Object[] parameters = values;
 
         // config via Query annotation (dynamicQuery = false)
@@ -420,9 +357,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         return transformQueryCursor(qry, returnStgy, parameters, qryCursor);
     }
 
-    /**
-     * {@inheritDoc} @return the query method
-     */
+    /** {@inheritDoc} */
     @Override public QueryMethod getQueryMethod() {
         return new QueryMethod(mtd, metadata, factory);
     }
@@ -434,28 +369,35 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         int index = -1;
         while (it.hasNext()) {
             T parameter = it.next();
+
             if (DynamicQueryConfig.class.isAssignableFrom(parameter.getType())) {
                 if (found) {
                     throw new IllegalStateException("Invalid '" + method.getName() + "' repository method signature. "
                         + "Only ONE DynamicQueryConfig parameter is allowed");
                 }
+
                 found = true;
                 index = i;
             }
+
             i++;
         }
         return index;
     }
 
+    /** */
     private synchronized IgniteBinaryImpl binary() {
         if (igniteBinary == null)
             igniteBinary = (IgniteBinaryImpl)ignite.binary();
+
         return igniteBinary;
     }
 
+    /** */
     private synchronized BinaryType binType() {
         if (igniteBinType == null)
             igniteBinType = binary().type(type);
+
         return igniteBinType;
     }
 
@@ -501,7 +443,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      * @return if {@code mtd} return type is assignable from {@code cls}
      */
     private boolean hasAssignableGenericReturnTypeFrom(Class<?> cls, Method mtd) {
-
         Type genericReturnType = mtd.getGenericReturnType();
 
         if (!(genericReturnType instanceof ParameterizedType))
@@ -530,7 +471,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     }
 
     /**
-     * when select fields by query H2 returns Timestamp for types java.util.Date and java.qryStr.Timestamp
+     * When select fields by query H2 returns Timestamp for types java.util.Date and java.qryStr.Timestamp
      *
      * @see org.apache.ignite.internal.processors.query.h2.H2DatabaseType map.put(Timestamp.class, TIMESTAMP)
      * map.put(java.util.Date.class, TIMESTAMP) map.put(java.qryStr.Date.class, DATE)
@@ -538,6 +479,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private static <T> T fixExpectedType(final Object object, final Class<T> expected) {
         if (expected != null && object instanceof java.sql.Timestamp && expected.equals(java.util.Date.class))
             return (T)new java.util.Date(((java.sql.Timestamp)object).getTime());
+
         return (T)object;
     }
 
@@ -547,11 +489,13 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private IgniteQuery getQuery(@Nullable DynamicQueryConfig cfg) {
         if (staticQuery != null)
             return staticQuery;
+
         if (cfg != null && (StringUtils.hasText(cfg.value()) || cfg.textQuery())) {
             return new IgniteQuery(cfg.value(),
                 !cfg.textQuery() && (isFieldQuery(cfg.value()) || cfg.forceFieldsQuery()), cfg.textQuery(),
                 false, IgniteQueryGenerator.getOptions(mtd));
         }
+
         throw new IllegalStateException("Unable to obtain a valid query. When passing dynamicQuery = true via org"
             + ".apache.ignite.springdata.repository.config.Query annotation, you must"
             + " provide a non null method parameter of type DynamicQueryConfig with a "
@@ -564,8 +508,10 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private ReturnStrategy getReturnStgy(IgniteQuery qry) {
         if (staticReturnStgy != null)
             return staticReturnStgy;
+
         if (qry != null)
             return calcReturnType(mtd, qry.isFieldQuery());
+
         throw new IllegalStateException("Unable to obtain a valid return strategy. When passing dynamicQuery = true "
             + "via org.apache.ignite.springdata.repository.config.Query annotation, "
             + "you must provide a non null method parameter of type "
@@ -601,7 +547,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         ReturnStrategy returnStgy,
         Object[] prmtrs,
         QueryCursor qryCursor) {
-
         final Class<?> returnClass;
 
         if (hasProjection) {
@@ -727,7 +672,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
     private Object[] extractBindableValues(Object[] values,
         Parameters<?, ?> queryMethodParams,
         List<ParameterBinding> queryBindings) {
-
         // no binding params then exit
         if (queryBindings.isEmpty())
             return values;
@@ -786,7 +730,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      */
     @NotNull
     private Query prepareQuery(IgniteQuery qry, DynamicQueryConfig config, ReturnStrategy returnStgy, Object[] values) {
-
         Object[] parameters = values;
 
         String queryString = qry.qryStr();
@@ -796,7 +739,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         checkRequiredPageable(returnStgy, values);
 
         if (!qry.isTextQuery()) {
-
             if (!qry.isAutogenerated()) {
                 StringQuery squery = new ExpressionBasedStringQuery(queryString, metadata, expressionParser);
                 queryString = squery.getQueryString();
@@ -840,7 +782,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
                 if (config.parts() != null && config.parts().length > 0)
                     sqlFieldsQry.setPartitions(config.parts());
 
-                sqlFieldsQry.setReplicatedOnly(config.replicatedOnly());
                 sqlFieldsQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
 
                 query = sqlFieldsQry;
@@ -851,16 +792,16 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
 
                 sqlQry.setDistributedJoins(config.distributedJoins());
                 sqlQry.setLocal(config.local());
+
                 if (config.parts() != null && config.parts().length > 0)
                     sqlQry.setPartitions(config.parts());
-                sqlQry.setReplicatedOnly(config.replicatedOnly());
+
                 sqlQry.setTimeout(config.timeout(), TimeUnit.MILLISECONDS);
 
                 query = sqlQry;
             }
         }
         else {
-
             int pageSize = -1;
 
             switch (qry.options()) {
@@ -899,6 +840,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         return query;
     }
 
+    /** */
     private static Map<String, Object> rowToMap(final List<?> row, final List<GridQueryFieldMetadata> meta) {
         // use treemap with case insensitive property name
         final TreeMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -912,7 +854,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         return map;
     }
 
-    /*
+    /**
      * convert row ( with list of field values) into domain entity
      */
     private <V> V rowToEntity(final IgniteBinaryImpl binary,
@@ -953,7 +895,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
         final BinaryType binType,
         final GridQueryFieldMetadata fieldMeta) {
         try {
-
             final String fieldId = fieldMeta.schemaName() + "." + fieldMeta.typeName() + "." + fieldMeta.fieldName();
 
             if (binaryFieldClass.containsKey(fieldId))
@@ -1038,7 +979,6 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
      * @param <V> transformed output type
      */
     public static class QueryCursorWrapper<T, V> extends AbstractCollection<V> implements QueryCursor<V> {
-
         /**
          * Delegate query cursor.
          */
@@ -1060,14 +1000,12 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
             this.transformer = transformer;
         }
 
-        /**
-         * {@inheritDoc} @return the iterator
-         */
+        /** {@inheritDoc} */
         @Override public Iterator<V> iterator() {
-
             final Iterator<T> it = delegate.iterator();
 
             return new Iterator<V>() {
+                /** */
                 @Override public boolean hasNext() {
                     if (!it.hasNext()) {
                         U.closeQuiet(delegate);
@@ -1076,6 +1014,7 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
                     return true;
                 }
 
+                /** */
                 @Override public V next() {
                     final V r = transformer.apply(it.next());
                     if (r != null)
@@ -1085,16 +1024,12 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
             };
         }
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         @Override public void close() {
             U.closeQuiet(delegate);
         }
 
-        /**
-         * {@inheritDoc} @return the all
-         */
+        /** {@inheritDoc} */
         @Override public List<V> getAll() {
             final List<V> data = new ArrayList<>();
             delegate.forEach(i -> data.add(transformer.apply(i)));
@@ -1102,13 +1037,9 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
             return data;
         }
 
-        /**
-         * {@inheritDoc} @return the int
-         */
+        /** {@inheritDoc} */
         @Override public int size() {
             return 0;
         }
-
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java
index 3c46aae..f3bae41 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/QueryUtils.java
@@ -118,7 +118,6 @@ public abstract class QueryUtils {
     private static final Pattern FUNCTION_PATTERN;
 
     static {
-
         StringBuilder builder = new StringBuilder();
         builder.append("(?<=from)"); // from as starting delimiter
         builder.append("(?:\\s)+"); // at least one space separating
@@ -165,7 +164,7 @@ public abstract class QueryUtils {
      * Private constructor to prevent instantiation.
      */
     private QueryUtils() {
-
+        // No-op.
     }
 
     /**
@@ -179,7 +178,6 @@ public abstract class QueryUtils {
     public static String getExistsQueryString(String entityName,
         String cntQryPlaceHolder,
         Iterable<String> idAttrs) {
-
         String whereClause = Streamable.of(idAttrs).stream() //
             .map(idAttribute -> String.format(EQUALS_CONDITION_STRING, "x", idAttribute,
                 idAttribute)) //
@@ -194,10 +192,9 @@ public abstract class QueryUtils {
      * @param template   must not be {@literal null}.
      * @param entityName must not be {@literal null}.
      * @return the template with placeholders replaced by the {@literal entityName}. Guaranteed to be not {@literal
-     * null}.
+     *     null}.
      */
     public static String getQueryString(String template, String entityName) {
-
         Assert.hasText(entityName, "Entity name must not be null or empty!");
 
         return String.format(template, entityName);
@@ -210,12 +207,10 @@ public abstract class QueryUtils {
      * @return a {@literal Set} of aliases used in the query. Guaranteed to be not {@literal null}.
      */
     static Set<String> getOuterJoinAliases(String qry) {
-
         Set<String> result = new HashSet<>();
         Matcher matcher = JOIN_PATTERN.matcher(qry);
 
         while (matcher.find()) {
-
             String alias = matcher.group(QUERY_JOIN_ALIAS_GROUP_INDEX);
             if (StringUtils.hasText(alias))
                 result.add(alias);
@@ -231,12 +226,10 @@ public abstract class QueryUtils {
      * @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
      */
     static Set<String> getFunctionAliases(String qry) {
-
         Set<String> result = new HashSet<>();
         Matcher matcher = FUNCTION_PATTERN.matcher(qry);
 
         while (matcher.find()) {
-
             String alias = matcher.group(1);
 
             if (StringUtils.hasText(alias))
@@ -251,12 +244,9 @@ public abstract class QueryUtils {
      *
      * @param qry must not be {@literal null}.
      * @return Might return {@literal null}.
-     * @deprecated use {@link DeclaredQuery#getAlias()} instead.
      */
     @Nullable
-    @Deprecated
-    public static String detectAlias(String qry) {
-
+    static String detectAlias(String qry) {
         Matcher matcher = ALIAS_MATCH.matcher(qry);
 
         return matcher.find() ? matcher.group(2) : null;
@@ -265,34 +255,17 @@ public abstract class QueryUtils {
     /**
      * Creates a count projected query from the given original query.
      *
-     * @param originalQry must not be {@literal null} or empty.
-     * @return Guaranteed to be not {@literal null}.
-     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
-     */
-    @Deprecated
-    public static String createCountQueryFor(String originalQry) {
-        return createCountQueryFor(originalQry, null);
-    }
-
-    /**
-     * Creates a count projected query from the given original query.
-     *
      * @param originalQry   must not be {@literal null}.
      * @param cntProjection may be {@literal null}.
      * @return a query String to be used a count query for pagination. Guaranteed to be not {@literal null}.
-     * @since 1.6
-     * @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
      */
-    @Deprecated
-    public static String createCountQueryFor(String originalQry, @Nullable String cntProjection) {
-
+    static String createCountQueryFor(String originalQry, @Nullable String cntProjection) {
         Assert.hasText(originalQry, "OriginalQuery must not be null or empty!");
 
         Matcher matcher = COUNT_MATCH.matcher(originalQry);
         String countQuery;
 
         if (cntProjection == null) {
-
             String variable = matcher.matches() ? matcher.group(VARIABLE_NAME_GROUP_INDEX) : null;
             boolean useVariable = variable != null && StringUtils.hasText(variable) && !variable.startsWith("new")
                 && !variable.startsWith("count(") && !variable.contains(",");
@@ -307,25 +280,12 @@ public abstract class QueryUtils {
     }
 
     /**
-     * Returns whether the given query contains named parameters.
-     *
-     * @param qry can be {@literal null} or empty.
-     * @return whether the given query contains named parameters.
-     */
-    @Deprecated
-    static boolean hasNamedParameter(@Nullable String qry) {
-        return StringUtils.hasText(qry) && NAMED_PARAMETER.matcher(qry).find();
-    }
-
-    /**
      * Returns whether the given JPQL query contains a constructor expression.
      *
      * @param qry must not be {@literal null} or empty.
      * @return boolean
-     * @since 1.10
      */
     public static boolean hasConstructorExpression(String qry) {
-
         Assert.hasText(qry, "Query must not be null or empty!");
 
         return CONSTRUCTOR_EXPRESSION.matcher(qry).find();
@@ -336,15 +296,12 @@ public abstract class QueryUtils {
      *
      * @param qry must not be {@literal null} or empty.
      * @return projection
-     * @since 1.10.2
      */
     public static String getProjection(String qry) {
-
         Assert.hasText(qry, "Query must not be null or empty!");
 
         Matcher matcher = PROJECTION_CLAUSE.matcher(qry);
         String projection = matcher.find() ? matcher.group(1) : "";
         return projection.trim();
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java
index bad39b2..1c2366e 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/query/StringQuery.java
@@ -25,7 +25,6 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.springframework.data.repository.query.SpelQueryContext;
 import org.springframework.data.repository.query.SpelQueryContext.SpelExtractor;
-
 import org.springframework.data.domain.Range;
 import org.springframework.data.domain.Range.Bound;
 import org.springframework.data.repository.query.parser.Part.Type;
@@ -51,18 +50,23 @@ import static org.springframework.util.ObjectUtils.nullSafeHashCode;
  * @author Jens Schauder
  */
 class StringQuery implements DeclaredQuery {
-
+    /** */
     private final String query;
 
+    /** */
     private final List<ParameterBinding> bindings;
 
+    /** */
     @Nullable
     private final String alias;
 
+    /** */
     private final boolean hasConstructorExpression;
 
+    /** */
     private final boolean containsPageableInSpel;
 
+    /** */
     private final boolean usesJdbcStyleParameters;
 
     /**
@@ -70,8 +74,7 @@ class StringQuery implements DeclaredQuery {
      *
      * @param query must not be {@literal null} or empty.
      */
-    @SuppressWarnings("deprecation") StringQuery(String query) {
-
+    StringQuery(String query) {
         Assert.hasText(query, "Query must not be null or empty!");
 
         bindings = new ArrayList<>();
@@ -94,84 +97,64 @@ class StringQuery implements DeclaredQuery {
         return !bindings.isEmpty();
     }
 
+    /** */
     String getProjection() {
         return QueryUtils.getProjection(query);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getParameterBindings()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#getParameterBindings()
+    /** {@inheritDoc} */
     @Override public List<ParameterBinding> getParameterBindings() {
         return bindings;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#deriveCountQuery(java.lang.String, java.lang
-     * .String)
-     */
-    @SuppressWarnings("deprecation")
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#deriveCountQuery(java.lang.String, java.lang
+    /** {@inheritDoc} */
     @Override public DeclaredQuery deriveCountQuery(@Nullable String countQuery,
         @Nullable String countQueryProjection) {
-
         return DeclaredQuery
             .of(countQuery != null ? countQuery : QueryUtils.createCountQueryFor(query, countQueryProjection));
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesJdbcStyleParameters()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#usesJdbcStyleParameters()
+    /** */
     @Override public boolean usesJdbcStyleParameters() {
         return usesJdbcStyleParameters;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getQueryString()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#getQueryString()
+    /** {@inheritDoc} */
     @Override public String getQueryString() {
         return query;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#getAlias()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#getAlias()
+    /** {@inheritDoc} */
     @Override @Nullable
     public String getAlias() {
         return alias;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasConstructorExpression()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#hasConstructorExpression()
+    /** {@inheritDoc} */
     @Override public boolean hasConstructorExpression() {
         return hasConstructorExpression;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#isDefaultProjection()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#isDefaultProjection()
+    /** {@inheritDoc} */
     @Override public boolean isDefaultProjection() {
         return getProjection().equalsIgnoreCase(alias);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#hasNamedParameter()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#hasNamedParameter()
+    /** {@inheritDoc} */
     @Override public boolean hasNamedParameter() {
         return bindings.stream().anyMatch(b -> b.getName() != null);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see org.springframework.data.jpa.repository.query.DeclaredQuery#usesPaging()
-     */
+    // See org.springframework.data.jpa.repository.query.DeclaredQuery#usesPaging()
+    /** {@inheritDoc} */
     @Override public boolean usesPaging() {
         return containsPageableInSpel;
     }
@@ -182,24 +165,40 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     enum ParameterBindingParser {
+        /** */
         INSTANCE;
+
+        /** */
         private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
+
+        /** */
         public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
         // .....................................................................^ not followed by a hash or a letter.
         // .................................................................^ zero or more digits.
         // .............................................................^ start with a question mark.
+
+        /** */
         private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile(POSITIONAL_OR_INDEXED_PARAMETER);
+
+        /** */
         private static final Pattern PARAMETER_BINDING_PATTERN;
+
+        /** */
         private static final String MESSAGE =
             "Already found parameter binding with same index / parameter name but differing binding type! "
                 + "Already have: %s, found %s! If you bind a parameter multiple times make sure they use the same "
                 + "binding.";
+
+        /** */
         private static final int INDEXED_PARAMETER_GROUP = 4;
+
+        /** */
         private static final int NAMED_PARAMETER_GROUP = 6;
+
+        /** */
         private static final int COMPARISION_TYPE_GROUP = 1;
 
         static {
-
             List<String> keywords = new ArrayList<>();
 
             for (ParameterBindingType type : ParameterBindingType.values()) {
@@ -234,7 +233,6 @@ class StringQuery implements DeclaredQuery {
         private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String query,
             List<ParameterBinding> bindings,
             Metadata queryMeta) {
-
             int greatestParamIdx = tryFindGreatestParameterIndexIn(query);
             boolean parametersShouldBeAccessedByIdx = greatestParamIdx != -1;
 
@@ -256,8 +254,8 @@ class StringQuery implements DeclaredQuery {
             int expressionParamIdx = parametersShouldBeAccessedByIdx ? greatestParamIdx : 0;
 
             boolean usesJpaStyleParameters = false;
-            while (matcher.find()) {
 
+            while (matcher.find()) {
                 if (quotedAreas.isQuoted(matcher.start()))
                     continue;
 
@@ -275,7 +273,6 @@ class StringQuery implements DeclaredQuery {
 
                 expressionParamIdx++;
                 if (paramIdxStr != null && paramIdxStr.isEmpty()) {
-
                     queryMeta.usesJdbcStyleParameters = true;
                     paramIdx = expressionParamIdx;
                 }
@@ -296,9 +293,7 @@ class StringQuery implements DeclaredQuery {
                 }
 
                 switch (ParameterBindingType.of(typeSrc)) {
-
                     case LIKE:
-
                         Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2));
                         replacement = matcher.group(3);
 
@@ -313,7 +308,6 @@ class StringQuery implements DeclaredQuery {
                         break;
 
                     case IN:
-
                         if (paramIdx != null)
                             checkAndRegister(new InParameterBinding(paramIdx, expression), bindings);
                         else
@@ -335,6 +329,7 @@ class StringQuery implements DeclaredQuery {
             return resultingQry;
         }
 
+        /** */
         private static SpelExtractor createSpelExtractor(String queryWithSpel,
             boolean parametersShouldBeAccessedByIndex,
             int greatestParameterIndex) {
@@ -360,8 +355,8 @@ class StringQuery implements DeclaredQuery {
             return SpelQueryContext.of(indexToParameterName, parameterNameToReplacement).parse(queryWithSpel);
         }
 
+        /** */
         private static String replaceFirst(String text, String substring, String replacement) {
-
             int index = text.indexOf(substring);
             if (index < 0)
                 return text;
@@ -369,16 +364,16 @@ class StringQuery implements DeclaredQuery {
             return text.substring(0, index) + replacement + text.substring(index + substring.length());
         }
 
+        /** */
         @Nullable
         private static Integer getParameterIndex(@Nullable String parameterIndexString) {
-
             if (parameterIndexString == null || parameterIndexString.isEmpty())
                 return null;
             return Integer.valueOf(parameterIndexString);
         }
 
+        /** */
         private static int tryFindGreatestParameterIndexIn(String query) {
-
             Matcher parameterIndexMatcher = PARAMETER_BINDING_BY_INDEX.matcher(query);
 
             int greatestParameterIndex = -1;
@@ -393,6 +388,7 @@ class StringQuery implements DeclaredQuery {
             return greatestParameterIndex;
         }
 
+        /** */
         private static void checkAndRegister(ParameterBinding binding, List<ParameterBinding> bindings) {
 
             bindings.stream() //
@@ -412,12 +408,20 @@ class StringQuery implements DeclaredQuery {
         private enum ParameterBindingType {
             // Trailing whitespace is intentional to reflect that the keywords must be used with at least one whitespace
             // character, while = does not.
+            /** */
             LIKE("like "),
+
+            /** */
             IN("in "),
+
+            /** */
             AS_IS(null);
-            private final @Nullable
-            String keyword;
 
+            /** */
+            @Nullable
+            private final String keyword;
+
+            /** */
             ParameterBindingType(@Nullable String keyword) {
                 this.keyword = keyword;
             }
@@ -438,7 +442,6 @@ class StringQuery implements DeclaredQuery {
              * #AS_IS} in case no other {@link ParameterBindingType} could be found.
              */
             static ParameterBindingType of(String typeSource) {
-
                 if (!StringUtils.hasText(typeSource))
                     return AS_IS;
 
@@ -458,12 +461,15 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     static class ParameterBinding {
+        /** */
         @Nullable
         private final String name;
 
+        /** */
         @Nullable
         private final String expression;
 
+        /** */
         @Nullable
         private final Integer position;
 
@@ -524,7 +530,6 @@ class StringQuery implements DeclaredQuery {
         /**
          * @return the name
          * @throws IllegalStateException if the name is not available.
-         * @since 2.0
          */
         String getRequiredName() throws IllegalStateException {
 
@@ -547,7 +552,6 @@ class StringQuery implements DeclaredQuery {
         /**
          * @return the position
          * @throws IllegalStateException if the position is not available.
-         * @since 2.0
          */
         int getRequiredPosition() throws IllegalStateException {
 
@@ -566,10 +570,7 @@ class StringQuery implements DeclaredQuery {
             return expression != null;
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#hashCode()
-         */
+        /** */
         @Override public int hashCode() {
 
             int result = 17;
@@ -581,10 +582,7 @@ class StringQuery implements DeclaredQuery {
             return result;
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
+        /** */
         @Override public boolean equals(Object obj) {
 
             if (!(obj instanceof ParameterBinding))
@@ -596,10 +594,7 @@ class StringQuery implements DeclaredQuery {
                 && nullSafeEquals(expression, that.expression);
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#toString()
-         */
+        /** */
         @Override public String toString() {
             return String.format("ParameterBinding [name: %s, position: %d, expression: %s]", getName(), getPosition(),
                 getExpression());
@@ -613,11 +608,11 @@ class StringQuery implements DeclaredQuery {
             return valueToBind;
         }
 
+        /** */
         @Nullable
         public String getExpression() {
             return expression;
         }
-
     }
 
     /**
@@ -627,7 +622,6 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     static class InParameterBinding extends ParameterBinding {
-
         /**
          * Creates a new {@link InParameterBinding} for the parameter with the given name.
          */
@@ -647,7 +641,6 @@ class StringQuery implements DeclaredQuery {
          * @see org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding#prepare(java.lang.Object)
          */
         @Override public Object prepare(@Nullable Object value) {
-
             if (!ObjectUtils.isArray(value))
                 return value;
 
@@ -670,10 +663,11 @@ class StringQuery implements DeclaredQuery {
      * @author Thomas Darimont
      */
     static class LikeParameterBinding extends ParameterBinding {
-
+        /** */
         private static final List<Type> SUPPORTED_TYPES = Arrays.asList(Type.CONTAINING, Type.STARTING_WITH,
             Type.ENDING_WITH, Type.LIKE);
 
+        /** */
         private final Type type;
 
         /**
@@ -751,7 +745,6 @@ class StringQuery implements DeclaredQuery {
          */
         @Nullable
         @Override public Object prepare(@Nullable Object value) {
-
             if (value == null)
                 return null;
 
@@ -768,12 +761,8 @@ class StringQuery implements DeclaredQuery {
             }
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
+        /** */
         @Override public boolean equals(Object obj) {
-
             if (!(obj instanceof LikeParameterBinding))
                 return false;
 
@@ -782,10 +771,7 @@ class StringQuery implements DeclaredQuery {
             return super.equals(obj) && type.equals(that.type);
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#hashCode()
-         */
+        /** */
         @Override public int hashCode() {
 
             int result = super.hashCode();
@@ -795,10 +781,7 @@ class StringQuery implements DeclaredQuery {
             return result;
         }
 
-        /*
-         * (non-Javadoc)
-         * @see java.lang.Object#toString()
-         */
+        /** */
         @Override public String toString() {
             return String.format("LikeBinding [name: %s, position: %d, type: %s]", getName(), getPosition(), type);
         }
@@ -826,13 +809,12 @@ class StringQuery implements DeclaredQuery {
 
     }
 
+    /** */
     static class Metadata {
-
         /**
          * Uses jdbc style parameters.
          */
         private boolean usesJdbcStyleParameters;
-
     }
 
     /**
@@ -841,12 +823,12 @@ class StringQuery implements DeclaredQuery {
      *
      * @author Jens Schauder
      * @author Oliver Gierke
-     * @since 2.1
      */
     static class QuotationMap {
-
+        /** */
         private static final Collection<Character> QUOTING_CHARACTERS = Arrays.asList('"', '\'');
 
+        /** */
         private final List<Range<Integer>> quotedRanges = new ArrayList<>();
 
         /**
@@ -855,7 +837,6 @@ class StringQuery implements DeclaredQuery {
          * @param query can be {@literal null}.
          */
         public QuotationMap(@Nullable String query) {
-
             if (query == null)
                 return;
 
@@ -863,18 +844,15 @@ class StringQuery implements DeclaredQuery {
             int start = 0;
 
             for (int i = 0; i < query.length(); i++) {
-
                 char currentChar = query.charAt(i);
 
                 if (QUOTING_CHARACTERS.contains(currentChar)) {
-
                     if (inQuotation == null) {
 
                         inQuotation = currentChar;
                         start = i;
                     }
                     else if (currentChar == inQuotation) {
-
                         inQuotation = null;
 
                         quotedRanges.add(Range.from(Bound.inclusive(start)).to(Bound.inclusive(i)));
@@ -897,7 +875,5 @@ class StringQuery implements DeclaredQuery {
         public boolean isQuoted(int idx) {
             return quotedRanges.stream().anyMatch(r -> r.contains(idx));
         }
-
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/ConditionFalse.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/ConditionFalse.java
index b30c11b..a69dc8e 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/ConditionFalse.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/ConditionFalse.java
@@ -25,9 +25,7 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
  * Always false condition. Tells spring context never load bean with such Condition.
  */
 public class ConditionFalse implements Condition {
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
         return false;
     }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
index 036280b..9c04b38 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
@@ -101,6 +101,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         beanExpressionContext = new BeanExpressionContext(beanFactory, null);
     }
 
+    /** */
     private Ignite igniteForRepoConfig(RepositoryConfig config) {
         try {
             String igniteInstanceName = evaluateExpression(config.igniteInstance());
@@ -135,39 +136,27 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         }
     }
 
-    /**
-     * {@inheritDoc} @param <T>  the type parameter
-     *
-     * @param <ID>        the type parameter
-     * @param domainClass the domain class
-     * @return the entity information
-     */
+    /** {@inheritDoc} */
     @Override public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
         return new AbstractEntityInformation<T, ID>(domainClass) {
+            /** {@inheritDoc} */
             @Override public ID getId(T entity) {
                 return null;
             }
 
+            /** {@inheritDoc} */
             @Override public Class<ID> getIdType() {
                 return null;
             }
         };
     }
 
-    /**
-     * {@inheritDoc} @param metadata the metadata
-     *
-     * @return the repository base class
-     */
+    /** {@inheritDoc} */
     @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
         return IgniteRepositoryImpl.class;
     }
 
-    /**
-     * {@inheritDoc} @param repoItf the repo itf
-     *
-     * @return the repository metadata
-     */
+    /** {@inheritDoc} */
     @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
         Assert.notNull(repoItf, "Repository interface must be set.");
         Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
@@ -190,7 +179,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
     }
 
     /**
-     * evaluate the SpEL expression
+     * Evaluate the SpEL expression
      *
      * @param spelExpression SpEL expression
      * @return the result of execution of the SpEL expression
@@ -200,7 +189,7 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         return (String)resolver.evaluate(spelExpression, beanExpressionContext);
     }
 
-    /* control underline cache creation to avoid cache creation by mistake */
+    /** Control underlying cache creation to avoid cache creation by mistake */
     private IgniteCache getRepositoryCache(Class<?> repoIf) {
         Ignite ignite = repoToIgnite.get(repoIf);
 
@@ -221,27 +210,18 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
         return c;
     }
 
-    /**
-     * {@inheritDoc} @param metadata the metadata
-     *
-     * @return the target repository
-     */
+    /** {@inheritDoc} */
     @Override protected Object getTargetRepository(RepositoryInformation metadata) {
         Ignite ignite = repoToIgnite.get(metadata.getRepositoryInterface());
+
         return getTargetRepositoryViaReflection(metadata, ignite,
             getRepositoryCache(metadata.getRepositoryInterface()));
     }
 
-    /**
-     * {@inheritDoc} @param key the key
-     *
-     * @param evaluationContextProvider the evaluation context provider
-     * @return the query lookup strategy
-     */
+    /** {@inheritDoc} */
     @Override protected Optional<QueryLookupStrategy> getQueryLookupStrategy(final QueryLookupStrategy.Key key,
         QueryMethodEvaluationContextProvider evaluationContextProvider) {
         return Optional.of((mtd, metadata, factory, namedQueries) -> {
-
             final Query annotation = mtd.getAnnotation(Query.class);
             final Ignite ignite = repoToIgnite.get(metadata.getRepositoryInterface());
 
@@ -249,11 +229,14 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
                 .dynamicQuery())) {
 
                 String qryStr = annotation.value();
+
                 boolean annotatedIgniteQuery = !annotation.dynamicQuery() && (StringUtils.hasText(qryStr) || annotation
                     .textQuery());
+
                 IgniteQuery query = annotatedIgniteQuery ? new IgniteQuery(qryStr,
                     !annotation.textQuery() && (isFieldQuery(qryStr) || annotation.forceFieldsQuery()),
                     annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
+
                 if (key != QueryLookupStrategy.Key.CREATE) {
                     return new IgniteRepositoryQuery(ignite, metadata, query, mtd, factory,
                         getRepositoryCache(metadata.getRepositoryInterface()),
@@ -302,5 +285,4 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
             // insert
             qryUpperCase.matches("^\\s*INSERT\\b.*");
     }
-
 }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
index f56c68c..ece9f31 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
@@ -45,9 +45,7 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
  */
 public class IgniteRepositoryFactoryBean<T extends Repository<V, K>, V, K extends Serializable>
     extends RepositoryFactoryBeanSupport<T, V, K> implements ApplicationContextAware {
-    /**
-     * Application context.
-     */
+    /** */
     private ApplicationContext ctx;
 
     /**
@@ -57,16 +55,12 @@ public class IgniteRepositoryFactoryBean<T extends Repository<V, K>, V, K extend
         super(repoInterface);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
         this.ctx = ctx;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected RepositoryFactorySupport createRepositoryFactory() {
         return new IgniteRepositoryFactory(ctx);
     }
diff --git a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
index 9bf63ed..0e13ee9 100644
--- a/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.2/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
@@ -65,53 +65,31 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         this.ignite = ignite;
     }
 
-    /**
-     * {@inheritDoc} @return the ignite cache
-     */
+    /** {@inheritDoc} */
     @Override public IgniteCache<K, V> cache() {
         return cache;
     }
 
-    /**
-     * {@inheritDoc} @return the ignite
-     */
+    /** {@inheritDoc} */
     @Override public Ignite ignite() {
         return ignite;
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param key    the key
-     * @param entity the entity
-     * @return the s
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> S save(K key, S entity) {
         cache.put(key, entity);
 
         return entity;
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entities the entities
-     * @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> Iterable<S> save(Map<K, S> entities) {
         cache.putAll(entities);
 
         return entities.values();
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param key       the key
-     * @param entity    the entity
-     * @param expiryPlc the expiry policy
-     * @return the s
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> S save(K key, S entity, @Nullable ExpiryPolicy expiryPlc) {
         if (expiryPlc != null)
             cache.withExpiryPolicy(expiryPlc).put(key, entity);
@@ -120,13 +98,7 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         return entity;
     }
 
-    /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entities  the entities
-     * @param expiryPlc the expiry policy
-     * @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public <S extends V> Iterable<S> save(Map<K, S> entities, @Nullable ExpiryPolicy expiryPlc) {
         if (expiryPlc != null)
             cache.withExpiryPolicy(expiryPlc).putAll(entities);
@@ -136,60 +108,48 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
     }
 
     /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entity the entity
-     * @return the s
+     * Not implemented.
      */
     @Override public <S extends V> S save(S entity) {
         throw new UnsupportedOperationException("Use IgniteRepository.save(key,value) method instead.");
     }
 
     /**
-     * {@inheritDoc} @param <S>  the type parameter
-     *
-     * @param entities the entities
-     * @return the iterable
+     * Not implemented.
      */
     @Override public <S extends V> Iterable<S> saveAll(Iterable<S> entities) {
         throw new UnsupportedOperationException("Use IgniteRepository.save(Map<keys,value>) method instead.");
     }
 
-    /**
-     * {@inheritDoc} @param id the id
-     *
-     * @return the optional
-     */
+    /** {@inheritDoc} */
     @Override public Optional<V> findById(K id) {
         return Optional.ofNullable(cache.get(id));
     }
 
-    /**
-     * {@inheritDoc} @param id the id
-     *
-     * @return the boolean
-     */
+    /** {@inheritDoc} */
     @Override public boolean existsById(K id) {
         return cache.containsKey(id);
     }
 
-    /**
-     * {@inheritDoc} @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public Iterable<V> findAll() {
         final Iterator<Cache.Entry<K, V>> iter = cache.iterator();
 
         return new Iterable<V>() {
+            /** */
             @Override public Iterator<V> iterator() {
                 return new Iterator<V>() {
+                    /** {@inheritDoc} */
                     @Override public boolean hasNext() {
                         return iter.hasNext();
                     }
 
+                    /** {@inheritDoc} */
                     @Override public V next() {
                         return iter.next().getValue();
                     }
 
+                    /** {@inheritDoc} */
                     @Override public void remove() {
                         iter.remove();
                     }
@@ -198,11 +158,7 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         };
     }
 
-    /**
-     * {@inheritDoc} @param ids the ids
-     *
-     * @return the iterable
-     */
+    /** {@inheritDoc} */
     @Override public Iterable<V> findAllById(Iterable<K> ids) {
         if (ids instanceof Set)
             return cache.getAll((Set<K>)ids).values();
@@ -218,37 +174,27 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         return cache.getAll(keys).values();
     }
 
-    /**
-     * {@inheritDoc} @return the long
-     */
+    /** {@inheritDoc} */
     @Override public long count() {
         return cache.size(CachePeekMode.PRIMARY);
     }
 
-    /**
-     * {@inheritDoc} @param id the id
-     */
+    /** {@inheritDoc} */
     @Override public void deleteById(K id) {
         cache.remove(id);
     }
 
-    /**
-     * {@inheritDoc} @param entity the entity
-     */
+    /** {@inheritDoc} */
     @Override public void delete(V entity) {
         throw new UnsupportedOperationException("Use IgniteRepository.deleteById(key) method instead.");
     }
 
-    /**
-     * {@inheritDoc} @param entities the entities
-     */
+    /** {@inheritDoc} */
     @Override public void deleteAll(Iterable<? extends V> entities) {
         throw new UnsupportedOperationException("Use IgniteRepository.deleteAllById(keys) method instead.");
     }
 
-    /**
-     * {@inheritDoc} @param ids the ids
-     */
+    /** {@inheritDoc} */
     @Override public void deleteAllById(Iterable<K> ids) {
         if (ids instanceof Set) {
             cache.removeAll((Set<K>)ids);
@@ -268,11 +214,8 @@ public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRe
         cache.removeAll(keys);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public void deleteAll() {
         cache.clear();
     }
-
 }
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
index 7154619..d9de9b7 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfExpressionTest.java
@@ -32,30 +32,20 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
  * Test with using repository which is configured by Spring EL
  */
 public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTest {
-    /**
-     * Number of entries to store
-     */
+    /** Number of entries to store */
     private static final int CACHE_SIZE = 1000;
 
-    /**
-     * Repository.
-     */
+    /** Repository. */
     private static PersonExpressionRepository repo;
 
-    /**
-     * Context.
-     */
+    /** Context. */
     private static AnnotationConfigApplicationContext ctx;
 
-    /**
-     *
-     */
+    /** */
     @Rule
     public final ExpectedException expected = ExpectedException.none();
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
@@ -66,9 +56,7 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         repo = ctx.getBean(PersonExpressionRepository.class);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
 
@@ -77,9 +65,7 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         assertEquals(CACHE_SIZE, repo.count());
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         repo.deleteAll();
 
@@ -88,25 +74,21 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
         super.afterTest();
     }
 
-    /**
-     *
-     */
+    /** */
     private void fillInRepository() {
         for (int i = 0; i < CACHE_SIZE - 5; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
                 "lastName" + Integer.toHexString((i + 16) % 256)));
         }
 
-        repo.save((int)repo.count(), new Person("uniquePerson", "uniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
-        repo.save((int)repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("uniquePerson", "uniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
+        repo.save((int) repo.count(), new Person("nonUniquePerson", "nonUniqueLastName"));
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override protected void afterTestsStopped() {
         ctx.close();
     }
@@ -147,6 +129,7 @@ public class IgniteSpringDataCrudSelfExpressionTest extends GridCommonAbstractTe
             cacheNames.contains("PersonCache"));
     }
 
+    /** */
     @Test
     public void testCacheCountTWO() {
         Ignite ignite = ctx.getBean("igniteInstanceTWO", Ignite.class);
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
index 5b52092..38785ef 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
@@ -33,7 +33,7 @@ import org.junit.Test;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
 /**
- *
+ * CRUD tests.
  */
 public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     /** Repository. */
@@ -76,9 +76,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         super.afterTest();
     }
 
-    /**
-     *
-     */
+    /** */
     private void fillInRepository() {
         for (int i = 0; i < CACHE_SIZE - 5; i++) {
             repo.save(i, new Person("person" + Integer.toHexString(i),
@@ -97,9 +95,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         ctx.destroy();
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testPutGet() {
         Person person = new Person("some_name", "some_surname");
@@ -122,9 +118,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testPutAllGetAll() {
         LinkedHashMap<Integer, Person> map = new LinkedHashMap<>();
@@ -162,9 +156,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(map.size(), counter);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testGetAll() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -181,9 +173,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(repo.count(), counter);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testDelete() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -203,9 +193,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testDeleteSet() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -234,9 +222,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testDeleteAll() {
         assertEquals(CACHE_SIZE, repo.count());
@@ -247,7 +233,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete existing record
+     * Delete existing record.
      */
     @Test
     public void testDeleteByFirstName() {
@@ -259,7 +245,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete NON existing record
+     * Delete NON existing record.
      */
     @Test
     public void testDeleteExpression() {
@@ -269,7 +255,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete Multiple records due to where
+     * Delete Multiple records due to where.
      */
     @Test
     public void testDeleteExpressionMultiple() {
@@ -280,7 +266,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Remove should do the same than Delete
+     * Remove should do the same than Delete.
      */
     @Test
     public void testRemoveExpression() {
@@ -291,7 +277,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Delete unique record using lower case key word
+     * Delete unique record using lower case key word.
      */
     @Test
     public void testDeleteQuery() {
@@ -302,7 +288,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Try to delete with a wrong @Query
+     * Try to delete with a wrong @Query.
      */
     @Test
     public void testWrongDeleteQuery() {
@@ -320,7 +306,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     }
 
     /**
-     * Update with a @Query a record
+     * Update with a @Query a record.
      */
     @Test
     public void testUpdateQueryMixedCase() {
@@ -347,6 +333,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName1");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionNamedParameter() {
         final String newSecondName = "updatedUniqueSecondName2";
@@ -358,6 +345,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseDynamicProjectionNamedParameter() {
         final String newSecondName = "updatedUniqueSecondName2";
@@ -372,6 +360,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(personFullName.get(0).getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
+    /** */
     @Test
     public void testUpdateQueryOneMixedCaseDynamicProjectionNamedParameter() {
         final String newSecondName = "updatedUniqueSecondName2";
@@ -386,6 +375,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(personFullName.getFullName(), "uniquePerson updatedUniqueSecondName2");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionIndexedParameter() {
         final String newSecondName = "updatedUniqueSecondName3";
@@ -397,6 +387,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName3");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionIndexedParameterLuceneTextQuery() {
         final String newSecondName = "updatedUniqueSecondName4";
@@ -408,6 +399,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName4");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionNamedParameterAndTemplateDomainEntityVariable() {
         final String newSecondName = "updatedUniqueSecondName5";
@@ -419,6 +411,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
         assertEquals(person.get(0).getFullName(), "uniquePerson updatedUniqueSecondName5");
     }
 
+    /** */
     @Test
     public void testUpdateQueryMixedCaseProjectionNamedParameterWithSpELExtension() {
         final String newSecondName = "updatedUniqueSecondName6";
@@ -438,6 +431,7 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
     public void testWrongUpdateQuery() {
         final String newSecondName = "updatedUniqueSecondName";
         int rowsUpdated = 0;
+
         try {
             rowsUpdated = repo.setWrongFixedSecondName(newSecondName, "uniquePerson");
         }
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
index 25592a2..d35c781 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/IgniteSpringDataQueriesSelfTest.java
@@ -38,14 +38,10 @@ import org.springframework.data.domain.Sort;
  *
  */
 public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
-    /**
-     * Repository.
-     */
+    /** Repository. */
     private static PersonRepository repo;
 
-    /**
-     * Repository 2.
-     */
+    /** Repository 2. */
     private static PersonSecondRepository repo2;
 
     /**
@@ -53,9 +49,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
      */
     private static PersonRepositoryOtherIgniteInstance repoTWO;
 
-    /**
-     * Context.
-     */
+    /** Context. */
     private static AnnotationConfigApplicationContext ctx;
 
     /**
@@ -95,9 +89,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         ctx.destroy();
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testExplicitQuery() {
         List<Person> persons = repo.simpleQuery("person4a");
@@ -108,6 +100,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("person4a", person.getFirstName());
     }
 
+    /** */
     @Test
     public void testExplicitQueryTWO() {
         List<Person> persons = repoTWO.simpleQuery("TWOperson4a");
@@ -118,9 +111,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("TWOperson4a", person.getFirstName());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testEqualsPart() {
         List<Person> persons = repo.findByFirstName("person4e");
@@ -131,6 +122,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("person4e", person.getFirstName());
     }
 
+    /** */
     @Test
     public void testEqualsPartTWO() {
         List<Person> persons = repoTWO.findByFirstName("TWOperson4e");
@@ -141,9 +133,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertEquals("TWOperson4e", person.getFirstName());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testContainingPart() {
         List<Person> persons = repo.findByFirstNameContaining("person4");
@@ -154,6 +144,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(person.getFirstName().startsWith("person4"));
     }
 
+    /** */
     @Test
     public void testContainingPartTWO() {
         List<Person> persons = repoTWO.findByFirstNameContaining("TWOperson4");
@@ -164,9 +155,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(person.getFirstName().startsWith("TWOperson4"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testTopPart() {
         Iterable<Person> top = repo.findTopByFirstNameContaining("person4");
@@ -180,6 +169,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFirstName().startsWith("person4"));
     }
 
+    /** */
     @Test
     public void testTopPartTWO() {
         Iterable<Person> top = repoTWO.findTopByFirstNameContaining("TWOperson4");
@@ -193,9 +183,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFirstName().startsWith("TWOperson4"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testLikeAndLimit() {
         Iterable<Person> like = repo.findFirst10ByFirstNameLike("person");
@@ -211,6 +199,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, cnt);
     }
 
+    /** */
     @Test
     public void testLikeAndLimitTWO() {
         Iterable<Person> like = repoTWO.findFirst10ByFirstNameLike("TWOperson");
@@ -226,9 +215,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, cnt);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testCount() {
         int cnt = repo.countByFirstNameLike("person");
@@ -236,6 +223,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(1000, cnt);
     }
 
+    /** */
     @Test
     public void testCountTWO() {
         int cnt = repoTWO.countByFirstNameLike("TWOperson");
@@ -243,9 +231,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(1000, cnt);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testCount2() {
         int cnt = repo.countByFirstNameLike("person4");
@@ -253,6 +239,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cnt < 1000);
     }
 
+    /** */
     @Test
     public void testCount2TWO() {
         int cnt = repoTWO.countByFirstNameLike("TWOperson4");
@@ -260,9 +247,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cnt < 1000);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testPageable() {
         PageRequest pageable = PageRequest.of(1, 5, Sort.Direction.DESC, "firstName");
@@ -292,9 +277,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(10, firstNames.size());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testAndAndOr() {
         int cntAnd = repo.countByFirstNameLikeAndSecondNameLike("person1", "lastName1");
@@ -304,9 +287,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cntAnd <= cntOr);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testQueryWithSort() {
         List<Person> persons = repo.queryWithSort("^[a-z]+$", Sort.by(Sort.Direction.DESC, "secondName"));
@@ -322,9 +303,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testQueryWithPaging() {
         List<Person> persons = repo.queryWithPageable("^[a-z]+$", PageRequest.of(1, 7, Sort.Direction.DESC, "secondName"));
@@ -342,9 +321,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testQueryFields() {
         List<String> persons = repo.selectField("^[a-z]+$", PageRequest.of(1, 7, Sort.Direction.DESC, "secondName"));
@@ -352,9 +329,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(7, persons.size());
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testFindCacheEntries() {
         List<Cache.Entry<Integer, Person>> cacheEntries = repo.findBySecondNameLike("stName1");
@@ -365,9 +340,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertTrue(entry.getValue().getSecondName().contains("stName1"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testFindOneCacheEntry() {
         Cache.Entry<Integer, Person> cacheEntry = repo.findTopBySecondNameLike("tName18");
@@ -377,9 +350,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(cacheEntry.getValue().getSecondName().contains("tName18"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testFindOneValue() {
         PersonProjection person = repo.findTopBySecondNameStartingWith("lastName18");
@@ -389,9 +360,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertTrue(person.getFullName().split("\\s")[1].startsWith("lastName18"));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testSelectSeveralFields() {
         List<List> lists = repo.selectSeveralField("^[a-z]+$", PageRequest.of(2, 6));
@@ -405,9 +374,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         }
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testCountQuery() {
         int cnt = repo.countQuery(".*");
@@ -415,9 +382,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
         assertEquals(256, cnt);
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testSliceOfCacheEntries() {
         Slice<Cache.Entry<Integer, Person>> slice = repo2.findBySecondNameIsNot("lastName18", PageRequest.of(3, 4));
@@ -428,9 +393,7 @@ public class IgniteSpringDataQueriesSelfTest extends GridCommonAbstractTest {
             assertFalse("lastName18".equals(entry.getValue().getSecondName()));
     }
 
-    /**
-     *
-     */
+    /** */
     @Test
     public void testSliceOfLists() {
         Slice<List> lists = repo2.querySliceOfList("^[a-z]+$", PageRequest.of(0, 3));
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
index c418926..1443d5d 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/ApplicationConfiguration.java
@@ -29,15 +29,14 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.spel.spi.EvaluationContextExtension;
 
-/**
- *
- */
+/** */
 @Configuration
 @EnableIgniteRepositories
 public class ApplicationConfiguration {
-
+    /** */
     public static final String IGNITE_INSTANCE_ONE = "IGNITE_INSTANCE_ONE";
 
+    /** */
     public static final String IGNITE_INSTANCE_TWO = "IGNITE_INSTANCE_TWO";
 
     /**
@@ -52,11 +51,13 @@ public class ApplicationConfiguration {
         return bean;
     }
 
+    /** */
     @Bean
     public EvaluationContextExtension sampleSpELExtension() {
         return new SampleEvaluationContextExtension();
     }
 
+    /** */
     @Bean(value = "sampleExtensionBean")
     public SamplePassParamExtension sampleExtensionBean() {
         return new SamplePassParamExtension();
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
index 9aca003..23f8f8e 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/FullNameProjection.java
@@ -24,7 +24,6 @@ import org.springframework.beans.factory.annotation.Value;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public interface FullNameProjection {
-
     /**
      * Sample of using SpEL expression
      * @return
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
index c4cab06..a187a08 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonProjection.java
@@ -24,7 +24,7 @@ import org.springframework.beans.factory.annotation.Value;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public interface PersonProjection {
-
+    /** */
     String getFirstName();
 
     /**
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
index 59db22b..0a5826f 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
@@ -30,7 +30,7 @@ import org.springframework.data.domain.Sort;
 import org.springframework.data.repository.query.Param;
 
 /**
- *
+ * Test repository.
  */
 @RepositoryConfig(cacheName = "PersonCache")
 public interface PersonRepository extends IgniteRepository<Person, Integer> {
diff --git a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
index 7acdcb5..9db4343 100644
--- a/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
+++ b/modules/spring-data-2.2/src/test/java/org/apache/ignite/springdata/misc/SampleEvaluationContextExtension.java
@@ -22,7 +22,7 @@ import java.util.Map;
 import org.springframework.data.spel.spi.EvaluationContextExtension;
 
 /**
- * Sample EvaluationContext Extension for Spring Data 2.0
+ * Sample EvaluationContext Extension for Spring Data 2.2
  * <p>
  * Use SpEl expressions into your {@code @Query} definitions.
  * <p>
@@ -59,32 +59,35 @@ import org.springframework.data.spel.spi.EvaluationContextExtension;
  * @author Manuel Núñez Sánchez (manuel.nunez@hawkore.com)
  */
 public class SampleEvaluationContextExtension implements EvaluationContextExtension {
-
+    /** */
     private static final SamplePassParamExtension SAMPLE_PASS_PARAM_EXTENSION_INSTANCE = new SamplePassParamExtension();
 
+    /** */
     private static final Map<String, Object> properties = new HashMap<>();
 
+    /** */
     private static final String SAMPLE_EXTENSION_SPEL_VAR = "sampleExtension";
 
     static {
         properties.put(SAMPLE_EXTENSION_SPEL_VAR, SAMPLE_PASS_PARAM_EXTENSION_INSTANCE);
     }
 
+    /** */
     @Override public String getExtensionId() {
         return "HK-SAMPLE-PASS-PARAM-EXTENSION";
     }
 
+    /** */
     @Override public Map<String, Object> getProperties() {
         return properties;
     }
 
+    /** */
     public static class SamplePassParamExtension {
-
         // just return same param
+        /** */
         public Object transformParam(Object param) {
             return param;
         }
-
     }
-
 }