Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bump spring, java, and kotlin versions and refactor #66

Merged
merged 23 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
33ad2cb
chore: bump spring, java and kotlin versions
mlz11 Dec 26, 2023
370ade6
refactor: replace deprecated lowercase method
mlz11 Dec 26, 2023
4269e8e
fix: fix typo
mlz11 Dec 26, 2023
beb3cb3
refactor: element access should use indexed access operators whenever…
mlz11 Dec 26, 2023
ebe7d22
refactor: replace null check and collection size check with "isNullOr…
mlz11 Dec 26, 2023
29bf545
fix: fix typo
mlz11 Dec 26, 2023
20c2e8c
refactor: make searchSpecAnnotation private
mlz11 Dec 26, 2023
23272f5
refactor: private property should not start with an uppercase letter
mlz11 Dec 26, 2023
7352f21
refactor: use 'when' statement
mlz11 Dec 26, 2023
0698f63
chore: update CircleCI config
mlz11 Dec 26, 2023
6850215
refactor: remove duplicate plugin and dependency declarations in pom
mlz11 Dec 26, 2023
e2e84c2
chore: bump antlr version
mlz11 Dec 26, 2023
f68a353
chore: add dependency-check to pom
mlz11 Dec 26, 2023
5c4eecd
chore: bump h2 version to avoid vulnerability
mlz11 Dec 26, 2023
022aed0
chore: bump dependencies to avoid vulnerabilities
mlz11 Dec 26, 2023
09ef5b5
chore: bump project version
mlz11 Dec 27, 2023
fd3a054
chore: add variable for dependency-check-maven version in pom
mlz11 Dec 26, 2023
442dcd2
chore: update kotlin-maven-plugin compile phase
mlz11 Dec 28, 2023
c7a3444
chore: add .java-version file for jenv
mlz11 Dec 28, 2023
7173228
chore: make library available for applications running under jdk17
mlz11 Dec 28, 2023
d6bd519
refactor: use data class
mlz11 Dec 28, 2023
09d2348
chore: update README.md
mlz11 Dec 28, 2023
abf051a
chore: bump maven-gpg-plugin version
mlz11 Dec 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ version: 2.1
orbs:
codecov: codecov/codecov@1.0.2

parameters:
jdk-image:
type: string
default: cimg/openjdk:17.0

jobs:
test:
environment:
MAVEN_OPTS: -Xmx3200m
docker:
- image: circleci/openjdk:11-jdk
- image: << pipeline.parameters.jdk-image >>
working_directory: ~/project
steps:
- checkout
Expand Down
1 change: 1 addition & 0 deletions .java-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
17.0
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Please note that providing such a feature on your API does not come without risk
<!-- GETTING STARTED -->
## Getting Started

**Requirements** : JDK 8 or more.
**Requirements** : JDK 17 or more.
To get a local copy up and running follow these simple steps.

### Installation
Expand All @@ -91,7 +91,7 @@ Add the repo to your project inside your `pom.xml` file
<dependency>
<groupId>com.sipios</groupId>
<artifactId>spring-search</artifactId>
<version>0.2.0</version>
<version>0.3.0</version>
</dependency>
```

Expand Down Expand Up @@ -175,6 +175,40 @@ Request : `/cars?search=options.transmission:Auto`
Request : `/cars?search=creationyear:2018 AND price<300000 AND (color:Yellow OR color:Blue) AND options.transmission:Auto`
![complex example](./docs/images/complex-example.gif)

<!-- TROUBLESHOOTING -->
## Troubleshooting

If you get the following error ⬇️

> No primary or default constructor found for interface org.springframework.data.jpa.domain.Specification

You are free to opt for either of the two following solutions :
1. Add a `@Configuration` class to add our argument resolver to your project
```kotlin
// Kotlin
@Configuration
class SpringSearchResolverConf : WebMvcConfigurer {
override fun addArgumentResolvers(argumentResolvers: MutableList<HandlerMethodArgumentResolver>) {
argumentResolvers.add(SearchSpecificationResolver())
}
}
```
```java
// Java
@Configuration
public class SpringSearchResolverConf implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new SearchSpecificationResolver());
}
}
```

2. Add a `@ComponentScan` annotation to your project configuration class
```java
@ComponentScan(basePackages = {"com.your-application", "com.sipios.springsearch"})
```

<!-- ROADMAP -->
## Roadmap

Expand Down
61 changes: 39 additions & 22 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,26 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<version>3.1.7</version>
<relativePath /> <!-- lookup parent from repository --> <!-- lookup parent from repository -->
</parent>
<groupId>com.sipios</groupId>
<artifactId>spring-search</artifactId>
<version>0.2.5</version>
<version>0.2.6</version>
<name>spring-search</name>
<description>API for generating spring boot database queries</description>

<properties>
<java.version>1.8</java.version>
<kotlin.version>1.6.20</kotlin.version>
<antl4.version>4.9</antl4.version>
<java.version>17</java.version>
<kotlin.version>1.9.22</kotlin.version>
<jacoco-maven-plugin.version>0.8.4</jacoco-maven-plugin.version>
<h2.version>2.2.220</h2.version>
<jackson-databind.version>2.16.0</jackson-databind.version>
<snakeyaml.version>2.0</snakeyaml.version>
<dependency-check-maven.version>9.0.7</dependency-check-maven.version>
<antl4.version>4.13.1</antl4.version>
<grammar.package>com.sipios.springsearch.grammar</grammar.package>
<grammar.directory>com/sipios/springsearch/grammar</grammar.directory>
<jacoco-maven-plugin.version>0.8.4</jacoco-maven-plugin.version>
<project.testresult.directory>${project.build.directory}/test-results</project.testresult.directory>
</properties>

Expand All @@ -32,6 +36,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -44,6 +49,18 @@
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
Expand All @@ -52,10 +69,6 @@
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -79,11 +92,6 @@
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -112,18 +120,14 @@
<outputDirectory>${project.build.directory}/generated-sources/antlr4/${grammar.directory}</outputDirectory>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
Expand Down Expand Up @@ -161,7 +165,7 @@
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>target/generated-sources/antlr4</sourceDir>
</sourceDirs>
<jvmTarget>1.8</jvmTarget>
<jvmTarget>17</jvmTarget>
</configuration>
<dependencies>
<dependency>
Expand Down Expand Up @@ -291,6 +295,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>compile</id>
Expand Down Expand Up @@ -351,7 +356,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
Expand All @@ -368,6 +373,18 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>${dependency-check-maven.version}</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<scm>
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/sipios/springsearch/QueryVisitorImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.sipios.springsearch.grammar.QueryParser
import org.springframework.data.jpa.domain.Specification

class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryBaseVisitor<Specification<T>>() {
private val ValueRegExp = Regex(pattern = "^(\\*?)(.+?)(\\*?)$")
mlz11 marked this conversation as resolved.
Show resolved Hide resolved
private val valueRegExp = Regex(pattern = "^(\\*?)(.+?)(\\*?)$")
override fun visitOpQuery(ctx: QueryParser.OpQueryContext): Specification<T> {
val left = visit(ctx.left)
val right = visit(ctx.right)
Expand Down Expand Up @@ -43,7 +43,7 @@ class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryB
.replace("\\'", "'")
}

val matchResult = this.ValueRegExp.find(value!!)
val matchResult = this.valueRegExp.find(value!!)
val criteria = SearchCriteria(
key,
op,
Expand Down
23 changes: 11 additions & 12 deletions src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ class SearchCriteria // Change EQUALS into ENDS_WITH, CONTAINS, STARTS_WITH base
// Change EQUALS into ENDS_WITH, CONTAINS, STARTS_WITH based on the presence of * in the value
val startsWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX)
val endsWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX)
if (op === SearchOperation.EQUALS && startsWithAsterisk && endsWithAsterisk) {
op = SearchOperation.CONTAINS
} else if (op === SearchOperation.EQUALS && startsWithAsterisk) {
op = SearchOperation.ENDS_WITH
} else if (op === SearchOperation.EQUALS && endsWithAsterisk) {
op = SearchOperation.STARTS_WITH
op = when {
op === SearchOperation.EQUALS && startsWithAsterisk && endsWithAsterisk -> SearchOperation.CONTAINS
op === SearchOperation.EQUALS && startsWithAsterisk -> SearchOperation.ENDS_WITH
op === SearchOperation.EQUALS && endsWithAsterisk -> SearchOperation.STARTS_WITH
else -> op
}

// Change NOT_EQUALS into DOESNT_END_WITH, DOESNT_CONTAIN, DOESNT_START_WITH based on the presence of * in the value
if (op === SearchOperation.NOT_EQUALS && startsWithAsterisk && endsWithAsterisk) {
op = SearchOperation.DOESNT_CONTAIN
} else if (op === SearchOperation.NOT_EQUALS && startsWithAsterisk) {
op = SearchOperation.DOESNT_END_WITH
} else if (op === SearchOperation.NOT_EQUALS && endsWithAsterisk) {
op = SearchOperation.DOESNT_START_WITH
op = when {
op === SearchOperation.NOT_EQUALS && startsWithAsterisk && endsWithAsterisk -> SearchOperation.DOESNT_CONTAIN
op === SearchOperation.NOT_EQUALS && startsWithAsterisk -> SearchOperation.DOESNT_END_WITH
op === SearchOperation.NOT_EQUALS && endsWithAsterisk -> SearchOperation.DOESNT_START_WITH
else -> op
}
}
this.operation = op
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/com/sipios/springsearch/SpecificationImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package com.sipios.springsearch

import com.sipios.springsearch.anotation.SearchSpec
import com.sipios.springsearch.strategies.ParsingStrategy
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Path
import jakarta.persistence.criteria.Predicate
import jakarta.persistence.criteria.Root
import java.util.ArrayList
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.Path
import javax.persistence.criteria.Predicate
import javax.persistence.criteria.Root
import org.springframework.data.jpa.domain.Specification
import org.springframework.http.HttpStatus
import org.springframework.web.server.ResponseStatusException
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/com/sipios/springsearch/SpecificationsBuilder.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.sipios.springsearch

import com.sipios.springsearch.anotation.SearchSpec
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.Predicate
import javax.persistence.criteria.Root
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Predicate
import jakarta.persistence.criteria.Root
import org.springframework.data.jpa.domain.Specification

class SpecificationsBuilder<U>(searchSpecAnnotation: SearchSpec) {
Expand All @@ -20,7 +20,7 @@ class SpecificationsBuilder<U>(searchSpecAnnotation: SearchSpec) {

/**
* This function expect a search string to have been provided.
* The search string has been transformed into a Expression Queue with the format: [OR, value>100, AND, value<1000, label:*MONO*]
* The search string has been transformed into an Expression Queue with the format: [OR, value>100, AND, value<1000, label:*MONO*]
*
* @return A list of specification used to filter the underlying object using JPA specifications
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ annotation class SearchSpec(
val searchParam: String = "search",

/**
* A flag to indicate if the search needs to be case sensitive or not
* A flag to indicate if the search needs to be case-sensitive or not
*/
val caseSensitiveFlag: Boolean = true
)
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class SearchSpecificationResolver : HandlerMethodArgumentResolver {
private fun <T> buildSpecification(specClass: Class<T>, search: String?, searchSpecAnnotation: SearchSpec): Specification<T>? {
logger.debug("Building specification for class {}", specClass)
logger.debug("Search value found is {}", search)
if (search == null || search.isEmpty()) {
if (search.isNullOrEmpty()) {
return null
}
val specBuilder = SpecificationsBuilder<T>(searchSpecAnnotation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package com.sipios.springsearch.strategies

import com.fasterxml.jackson.databind.util.StdDateFormat
import com.sipios.springsearch.SearchOperation
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.Path
import jakarta.persistence.criteria.Predicate
import java.text.DateFormat
import java.util.Date
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.Path
import javax.persistence.criteria.Predicate
import kotlin.reflect.KClass

class DateStrategy : ParsingStrategy {
Expand All @@ -20,8 +20,8 @@ class DateStrategy : ParsingStrategy {
value: Any?
): Predicate? {
return when (ops) {
SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Date)
SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Date)
SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Date)
SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Date)
else -> super.buildPredicate(builder, path, fieldName, ops, value)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.sipios.springsearch.strategies

import com.sipios.springsearch.SearchOperation
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.Path
import javax.persistence.criteria.Predicate
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.Path
import jakarta.persistence.criteria.Predicate
import kotlin.reflect.KClass

class DoubleStrategy : ParsingStrategy {
Expand All @@ -15,8 +15,8 @@ class DoubleStrategy : ParsingStrategy {
value: Any?
): Predicate? {
return when (ops) {
SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Double)
SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Double)
SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Double)
SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Double)
else -> super.buildPredicate(builder, path, fieldName, ops, value)
}
}
Expand Down
Loading